Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge redundant document types #121

Merged
merged 3 commits into from
Feb 6, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 8 additions & 11 deletions Sources/BSONABI/BSON.AnyValue.swift
Original file line number Diff line number Diff line change
@@ -5,9 +5,9 @@ extension BSON
enum AnyValue:Sendable
{
/// A general embedded document.
case document(BSON.DocumentView)
case document(BSON.Document)
/// An embedded list-document.
case list(BSON.ListView)
case list(BSON.List)
/// A binary array.
case binary(BSON.BinaryView<ArraySlice<UInt8>>)
/// A boolean.
@@ -29,7 +29,7 @@ extension BSON
/// A javascript scope containing code. This variant is maintained for
/// backward-compatibility with older versions of BSON and
/// should not be generated. (Prefer ``javascript(_:)``.)
case javascriptScope(BSON.DocumentView, BSON.UTF8View<ArraySlice<UInt8>>)
case javascriptScope(BSON.Document, BSON.UTF8View<ArraySlice<UInt8>>)
/// The MongoDB max-key.
case max
/// UTC milliseconds since the Unix epoch.
@@ -411,16 +411,13 @@ extension BSON.AnyValue
///
/// > Complexity: O(1).
@inlinable public
var document:BSON.DocumentView?
var document:BSON.Document?
{
switch self
{
case .document(let document):
document
case .list(let list):
list.document
default:
nil
case .document(let document): document
case .list(let list): .init(list: list)
default: nil
}
}
/// Attempts to unwrap a list from this variant.
@@ -431,7 +428,7 @@ extension BSON.AnyValue
///
/// > Complexity: O(1).
@inlinable public
var list:BSON.ListView?
var list:BSON.List?
{
switch self
{
4 changes: 2 additions & 2 deletions Sources/BSONABI/Fields/BSON.FieldEncoder.swift
Original file line number Diff line number Diff line change
@@ -99,12 +99,12 @@ extension BSON.FieldEncoder
}

@inlinable public mutating
func encode(document:BSON.DocumentView)
func encode(document:BSON.Document)
{
self[.document].serialize(document: document)
}
@inlinable public mutating
func encode(list:BSON.ListView)
func encode(list:BSON.List)
{
self[.list].serialize(list: list)
}
2 changes: 1 addition & 1 deletion Sources/BSONABI/Fields/BSON.Key.swift
Original file line number Diff line number Diff line change
@@ -65,7 +65,7 @@ extension BSON.Key
///
/// Some applications that use BSON, such as MongoDB, consider `.`
/// characters significant.
@available(*, deprecated, message: "Prefer 'Mongo.KeyPath' instead.")
@available(*, deprecated, message: "Prefer 'Mongo.AnyKeyPath' instead.")
@inlinable public static
func / (self:Self, next:Self) -> Self
{
15 changes: 10 additions & 5 deletions Sources/BSONABI/IO/BSON.FrameTraversable.swift
Original file line number Diff line number Diff line change
@@ -28,9 +28,14 @@ protocol _BSONFrameTraversable
/// O(1) time.
init(slicing:ArraySlice<UInt8>) throws

/// The slice of bytes constituting the opaque content of this view.
/// The conforming type defines what portion of the original buffer
/// this slice includes, and it may not cover the entirety of the
/// argument originally passed to ``init(slicing:)``.
var slice:ArraySlice<UInt8> { get }
/// The slice of bytes constituting the opaque content of this view. The conforming type
/// defines what portion of the original buffer this slice includes, and it may not cover
/// the entirety of the argument originally passed to ``init(slicing:)``.
var bytes:ArraySlice<UInt8> { get }
}
extension BSON.FrameTraversable
{
@available(*, deprecated, renamed: "bytes")
@inlinable public
var slice:ArraySlice<UInt8> { self.bytes }
}
20 changes: 0 additions & 20 deletions Sources/BSONABI/IO/BSON.FrameView.swift

This file was deleted.

8 changes: 4 additions & 4 deletions Sources/BSONABI/IO/BSON.Input.swift
Original file line number Diff line number Diff line change
@@ -221,10 +221,10 @@ extension BSON.Input
return .string(try self.parse(as: BSON.UTF8View<ArraySlice<UInt8>>.self))

case .document:
return .document(try self.parse(as: BSON.DocumentView.self))
return .document(try self.parse(as: BSON.Document.self))

case .list:
return .list(try self.parse(as: BSON.ListView.self))
return .list(try self.parse(as: BSON.List.self))

case .binary:
return .binary(try self.parse(as: BSON.BinaryView<ArraySlice<UInt8>>.self))
@@ -259,8 +259,8 @@ extension BSON.Input
let _:Int32 = try self.parse(as: Int32.self)
let code:BSON.UTF8View<ArraySlice<UInt8>> = try self.parse(
as: BSON.UTF8View<ArraySlice<UInt8>>.self)
let scope:BSON.DocumentView = try self.parse(
as: BSON.DocumentView.self)
let scope:BSON.Document = try self.parse(
as: BSON.Document.self)
return .javascriptScope(scope, code)

case .int32:
12 changes: 6 additions & 6 deletions Sources/BSONABI/IO/BSON.OutputStream.swift
Original file line number Diff line number Diff line change
@@ -36,28 +36,28 @@ extension BSON.OutputStream
func serialize(utf8:BSON.UTF8View<some BidirectionalCollection<UInt8>>)
{
self.serialize(integer: utf8.header)
self.append(utf8.slice)
self.append(utf8.bytes)
self.append(0x00)
}
@inlinable public mutating
func serialize(binary:BSON.BinaryView<some RandomAccessCollection<UInt8>>)
{
self.serialize(integer: binary.header)
self.append(binary.subtype.rawValue)
self.append(binary.slice)
self.append(binary.bytes)
}
@inlinable public mutating
func serialize(document:BSON.DocumentView)
func serialize(document:BSON.Document)
{
self.serialize(integer: document.header)
self.append(document.slice)
self.append(document.bytes)
self.append(0x00)
}
@inlinable public mutating
func serialize(list:BSON.ListView)
func serialize(list:BSON.List)
{
self.serialize(integer: list.header)
self.append(list.slice)
self.append(list.bytes)
self.append(0x00)
}
}
161 changes: 145 additions & 16 deletions Sources/BSONABI/Primitives/BSON.Document.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
extension BSON
{
@available(*, deprecated, message: "BSON.DocumentView has been merged with BSON.Document")
public
typealias DocumentView = Document

/// The `Document` type models the “universal” BSON DSL.
///
/// It is expected that more-specialized BSON DSLs will wrap an
@@ -16,52 +20,177 @@ extension BSON
{
self.output = .init(preallocated: [])
}

/// Stores the argument in ``bytes`` unchanged.
///
/// > Complexity: O(1)
@inlinable public
init(bytes:ArraySlice<UInt8>)
{
self.output = .init(preallocated: bytes)
}
}
}
extension BSON.Document
extension BSON.Document:BSON.FrameTraversable
{
public
typealias Frame = BSON.DocumentFrame

/// Stores the argument in ``bytes`` unchanged. Equivalent to ``init(bytes:)``.
///
/// > Complexity: O(1)
@inlinable public
var bytes:ArraySlice<UInt8>
init(slicing bytes:ArraySlice<UInt8>)
{
self.output.destination
self.init(bytes: bytes)
}

/// The raw data backing this document. This slice *does not* include the trailing null byte
/// that typically appears after its inline field list.
@inlinable public
var bytes:ArraySlice<UInt8> { self.output.destination }
}
extension BSON.Document:ExpressibleByDictionaryLiteral
extension BSON.Document
{
/// Indicates if this document contains no fields.
@inlinable public
var isEmpty:Bool { self.bytes.isEmpty }

/// The length that would be encoded in this document’s prefixed header.
/// Equal to ``size``.
@inlinable public
var header:Int32 { .init(self.size) }

/// The size of this document when encoded with its header and trailing
/// null byte. This *is* the same as the length encoded in the header itself.
@inlinable public
var size:Int { 5 + self.bytes.count }

/// Rebinds the backing storage of this list to a ``BSON.Document``. This will cause the
/// list to be interpreted as a document with keys numbered from 0 in base-10.
@inlinable public
init(dictionaryLiteral:(String, Never)...)
init(list:BSON.List)
{
self.init(bytes: list.bytes)
}

@inlinable public mutating
func append(contentsOf other:Self)
{
self.init()
self.output.append(other.bytes)
}
}
extension BSON.Document:Equatable
{
/// Performs an exact byte-wise comparison on two documents. Does not parse or validate the
/// operands. Documents with the same fields in different orders will compare unequal!
@inlinable public static
func == (a:Self, b:Self) -> Bool { a.bytes.elementsEqual(b.bytes) }
}

extension BSON.Document
{
@available(*, deprecated, renamed: "init(bson:)")
/// Parses this document into key-value pairs in order, yielding each key-value
/// pair to the provided closure.
///
/// Unlike ``parse(_:)``, this method does not allocate storage for the parsed key-value
/// pairs. (But it does allocate storage to provide a ``String`` representation for
/// each visited key.)
///
/// > Complexity:
/// O(*n*), where *n* is the size of this document’s backing storage.
@inlinable public
init(_ bson:BSON.DocumentView)
func parse<CodingKey>(to decode:(CodingKey, BSON.AnyValue) throws -> ()) throws
where CodingKey:RawRepresentable<String>
{
self.init(bson: bson)
var input:BSON.Input = .init(self.bytes)
while let code:UInt8 = input.next()
{
let type:BSON.AnyType = try .init(code: code)
let key:String = try input.parse(as: String.self)
// We must parse the value always, even if we are ignoring the key
let value:BSON.AnyValue = try input.parse(variant: type)

if let key:CodingKey = .init(rawValue: key)
{
try decode(key, value)
}
}
}
/// Convert a native array-backed document view to a document.
/// Splits this document’s inline key-value pairs into an array.
///
/// Calling this convenience method is the same as calling ``parse(to:)`` and
/// collecting the yielded key-value pairs in an array.
///
/// > Complexity: O(1).
/// > Complexity:
/// O(*n*), where *n* is the size of this document’s backing storage.
@inlinable public
init(bson:BSON.DocumentView)
func parse<CodingKey, T>(
_ transform:(_ key:CodingKey, _ value:BSON.AnyValue) throws -> T) throws -> [T]
where CodingKey:RawRepresentable<String>
{
self.init(bytes: bson.slice)
var elements:[T] = []
try self.parse
{
elements.append(try transform($0, $1))
}
return elements
}
}
extension BSON.Document:ExpressibleByDictionaryLiteral
{
/// Creates a document containing the given fields, making two passes over
/// the list of fields in order to encode the output without reallocations.
/// The order of the fields will be preserved.
@inlinable public
init(fields:some Collection<(key:BSON.Key, value:BSON.AnyValue)>)
{
let size:Int = fields.reduce(0) { $0 + 2 + $1.key.rawValue.utf8.count + $1.value.size }
var output:BSON.Output = .init(capacity: size)
output.serialize(fields: fields)

assert(output.destination.count == size, """
precomputed size (\(size)) does not match output size (\(output.destination.count))
""")

self.init(bytes: output.destination)
}

/// Creates a document containing a single key-value pair.
@inlinable public
init(key:BSON.Key, value:BSON.AnyValue)
{
self.init(
fields: CollectionOfOne<(key:BSON.Key, value:BSON.AnyValue)>.init((key, value)))
}

@inlinable public
init(dictionaryLiteral:(BSON.Key, BSON.AnyValue)...)
{
self.init(fields: dictionaryLiteral)
}
}

extension BSON.Document
{
@inlinable public mutating
func append(contentsOf other:Self)
@available(*, deprecated, message: "BSON.Document is already a BSON.Document")
@inlinable public
init(_ bson:Self)
{
self.output.append(other.bytes)
self.init(bson: bson)
}

@available(*, deprecated, message: "BSON.Document is already a BSON.Document")
@inlinable public
init(bson:Self)
{
self.init(bytes: bson.slice)
}

@available(*, deprecated, renamed: "init(bytes:)")
@inlinable public
init(slice:ArraySlice<UInt8>)
{
self.init(bytes: slice)
}
}
Loading
Oops, something went wrong.
Loading
Oops, something went wrong.