diff --git a/.swiftformat b/.swiftformat
new file mode 100644
index 00000000..a391513b
--- /dev/null
+++ b/.swiftformat
@@ -0,0 +1,4 @@
+--rules braces,redundantSelf,duplicateImports,linebreakAtEndOfFile,redundantReturn,sortImports
+--swiftversion 5.9.1
+--allman true
+--self insert
diff --git a/Benchmarks/Package.resolved b/Benchmarks/Package.resolved
index 5c275dd9..da62c520 100644
--- a/Benchmarks/Package.resolved
+++ b/Benchmarks/Package.resolved
@@ -50,8 +50,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-atomics.git",
"state" : {
- "revision" : "6c89474e62719ddcc1e9614989fff2f68208fe10",
- "version" : "1.1.0"
+ "revision" : "cd142fd2f64be2100422d658e7411e39489da985",
+ "version" : "1.2.0"
}
},
{
@@ -59,8 +59,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-collections.git",
"state" : {
- "revision" : "937e904258d22af6e447a0b72c0bc67583ef64a2",
- "version" : "1.0.4"
+ "revision" : "a902f1823a7ff3c9ab2fba0f992396b948eda307",
+ "version" : "1.0.5"
}
},
{
@@ -95,8 +95,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio.git",
"state" : {
- "revision" : "2d8e6ca36fe3e8ed74b0883f593757a45463c34d",
- "version" : "2.53.0"
+ "revision" : "702cd7c56d5d44eeba73fdf83918339b26dc855c",
+ "version" : "2.62.0"
}
},
{
@@ -104,8 +104,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio-ssl.git",
"state" : {
- "revision" : "e866a626e105042a6a72a870c88b4c531ba05f83",
- "version" : "2.24.0"
+ "revision" : "320bd978cceb8e88c125dcbb774943a92f6286e9",
+ "version" : "2.25.0"
}
},
{
diff --git a/Package.resolved b/Package.resolved
index d3c0e64a..ef288f0f 100644
--- a/Package.resolved
+++ b/Package.resolved
@@ -23,8 +23,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/tayloraswift/swift-grammar",
"state" : {
- "revision" : "163ce5d4d88db7d94f2f4ca1cabcb2ae65af8af7",
- "version" : "0.3.3"
+ "revision" : "6db3dd8912fc7acb821021cd96677b2e0eeb09f0",
+ "version" : "0.3.4"
}
},
{
@@ -41,8 +41,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio.git",
"state" : {
- "revision" : "3db5c4aeee8100d2db6f1eaf3864afdad5dc68fd",
- "version" : "2.59.0"
+ "revision" : "702cd7c56d5d44eeba73fdf83918339b26dc855c",
+ "version" : "2.62.0"
}
},
{
diff --git a/Package.swift b/Package.swift
index 3076ed2c..f3c3a76a 100644
--- a/Package.swift
+++ b/Package.swift
@@ -16,7 +16,7 @@ let package:Package = .init(name: "swift-mongodb",
.library(name: "BSONDecoding", targets: ["BSONDecoding"]),
.library(name: "BSONEncoding", targets: ["BSONEncoding"]),
.library(name: "BSONTesting", targets: ["BSONTesting"]),
- .library(name: "BSONTypes", targets: ["BSONTypes"]),
+ .library(name: "BSONABI", targets: ["BSONABI"]),
.library(name: "BSON_Durations", targets: ["BSON_Durations"]),
.library(name: "BSON_OrderedCollections", targets: ["BSON_OrderedCollections"]),
@@ -25,7 +25,6 @@ let package:Package = .init(name: "swift-mongodb",
.library(name: "Durations", targets: ["Durations"]),
.library(name: "Durations_Atomics", targets: ["Durations_Atomics"]),
- .library(name: "Mongo", targets: ["Mongo"]),
.library(name: "MongoDB", targets: ["MongoDB"]),
.library(name: "MongoQL", targets: ["MongoQL"]),
.library(name: "MongoTesting", targets: ["MongoTesting"]),
@@ -36,7 +35,7 @@ let package:Package = .init(name: "swift-mongodb",
dependencies:
[
.package(url: "https://github.com/tayloraswift/swift-grammar", .upToNextMinor(
- from: "0.3.2")),
+ from: "0.3.4")),
.package(url: "https://github.com/tayloraswift/swift-hash", .upToNextMinor(
from: "0.5.0")),
@@ -47,7 +46,7 @@ let package:Package = .init(name: "swift-mongodb",
/// swift-nio has a low rate of breakage, and can be trusted with a major-only
/// version requirement.
- .package(url: "https://github.com/apple/swift-nio.git", from: "2.59.0"),
+ .package(url: "https://github.com/apple/swift-nio.git", from: "2.62.0"),
/// swift-nio-ssl has a low rate of breakage, and can be trusted with a
/// major-only version requirement.
.package(url: "https://github.com/apple/swift-nio-ssl.git", from: "2.25.0"),
@@ -63,21 +62,39 @@ let package:Package = .init(name: "swift-mongodb",
.target(name: "BSON",
dependencies:
[
- .target(name: "BSONStreaming"),
+ .target(name: "BSONDecoding"),
+ .target(name: "BSONEncoding"),
+ ],
+ exclude:
+ [
+ "README.md",
]),
- .target(name: "BSONTraversal"),
+ .target(name: "BSONABI",
+ exclude:
+ [
+ "README.md",
+ ]),
- .target(name: "BSONTypes",
+ .target(name: "BSONDecoding",
dependencies:
[
- .target(name: "BSONTraversal"),
+ .target(name: "BSONABI"),
+ .product(name: "TraceableErrors", package: "swift-grammar"),
+ ],
+ exclude:
+ [
+ "README.md",
]),
- .target(name: "BSONStreaming",
+ .target(name: "BSONEncoding",
dependencies:
[
- .target(name: "BSONTypes"),
+ .target(name: "BSONABI"),
+ ],
+ exclude:
+ [
+ "README.md",
]),
@@ -87,48 +104,31 @@ let package:Package = .init(name: "swift-mongodb",
.target(name: "BSON"),
]),
- .target(name: "BSONDecoding",
- dependencies:
- [
- .target(name: "BSON"),
- .product(name: "TraceableErrors", package: "swift-grammar"),
- ]),
-
- .target(name: "BSONEncoding",
- dependencies:
- [
- .target(name: "BSON"),
- ]),
-
.target(name: "BSONTesting",
dependencies:
[
- .target(name: "BSONEncoding"),
- .target(name: "BSONDecoding"),
+ .target(name: "BSON"),
.product(name: "Testing", package: "swift-grammar"),
]),
.target(name: "BSON_UUID",
dependencies:
[
- .target(name: "BSONDecoding"),
- .target(name: "BSONEncoding"),
+ .target(name: "BSON"),
.target(name: "UUID"),
]),
.target(name: "BSON_Durations",
dependencies:
[
- .target(name: "BSONDecoding"),
- .target(name: "BSONEncoding"),
+ .target(name: "BSON"),
.target(name: "Durations"),
]),
.target(name: "BSON_OrderedCollections",
dependencies:
[
- .target(name: "BSONDecoding"),
- .target(name: "BSONEncoding"),
+ .target(name: "BSON"),
.product(name: "OrderedCollections", package: "swift-collections"),
]),
@@ -166,17 +166,23 @@ let package:Package = .init(name: "swift-mongodb",
.target(name: "Mongo"),
+ .target(name: "MongoABI",
+ dependencies:
+ [
+ .target(name: "BSON"),
+ .target(name: "Mongo"),
+ ]),
+
.target(name: "MongoBuiltins",
dependencies:
[
- .target(name: "MongoSchema"),
+ .target(name: "MongoABI"),
]),
.target(name: "MongoClusters",
dependencies:
[
- .target(name: "BSONDecoding"),
- .target(name: "BSONEncoding"),
+ .target(name: "BSON"),
.target(name: "Durations"),
.target(name: "Mongo"),
.product(name: "TraceableErrors", package: "swift-grammar"),
@@ -186,7 +192,7 @@ let package:Package = .init(name: "swift-mongodb",
dependencies:
[
.target(name: "MongoClusters"),
- .target(name: "MongoSchema"),
+ .target(name: "MongoABI"),
.product(name: "NIOCore", package: "swift-nio"),
]),
@@ -197,6 +203,7 @@ let package:Package = .init(name: "swift-mongodb",
.target(name: "BSON_OrderedCollections"),
.target(name: "BSON_UUID"),
.target(name: "Durations_Atomics"),
+ .target(name: "MongoABI"),
.target(name: "MongoConfiguration"),
.target(name: "MongoExecutor"),
.target(name: "OnlineCDF"),
@@ -216,6 +223,7 @@ let package:Package = .init(name: "swift-mongodb",
.target(name: "MongoIO",
dependencies:
[
+ .target(name: "Mongo"),
.target(name: "MongoWire"),
.product(name: "NIOCore", package: "swift-nio"),
]),
@@ -228,14 +236,6 @@ let package:Package = .init(name: "swift-mongodb",
.target(name: "MongoQL"),
]),
- .target(name: "MongoSchema",
- dependencies:
- [
- .target(name: "BSONDecoding"),
- .target(name: "BSONEncoding"),
- .target(name: "Mongo"),
- ]),
-
.target(name: "MongoTesting",
dependencies:
[
@@ -249,6 +249,7 @@ let package:Package = .init(name: "swift-mongodb",
dependencies:
[
.target(name: "BSON"),
+ .target(name: "Mongo"),
.product(name: "CRC", package: "swift-hash"),
]),
@@ -277,9 +278,8 @@ let package:Package = .init(name: "swift-mongodb",
.executableTarget(name: "BSONIntegrationTests",
dependencies:
[
+ .target(name: "BSON"),
.target(name: "BSONReflection"),
- .target(name: "BSONDecoding"),
- .target(name: "BSONEncoding"),
.product(name: "Testing", package: "swift-grammar"),
]),
diff --git a/README.md b/README.md
index 4dd1e8b6..22760d46 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-***`mongodb`***
`0.8`
+***`mongodb`***
`0.9`
[![ci status](https://github.com/tayloraswift/swift-mongodb/actions/workflows/build.yml/badge.svg)](https://github.com/tayloraswift/swift-mongodb/actions/workflows/build.yml)
diff --git a/Sources/BSON/README.md b/Sources/BSON/README.md
new file mode 100644
index 00000000..e050b045
--- /dev/null
+++ b/Sources/BSON/README.md
@@ -0,0 +1,9 @@
+# ``/BSON``
+
+An umbrella module providing a BSON parser, encoder, and decoder.
+
+## Linking the BSON libraries
+
+This module re-exports the ``BSONABI``, ``BSONEncoding``, and ``BSONDecoding`` modules. Importing them directly is discouraged.
+
+Some BSON modules (currently ``BSONReflection`` and ``BSONTesting``) are considered ancillary and are not included in this umbrella module.
diff --git a/Sources/BSON/exports.swift b/Sources/BSON/exports.swift
index 0342acab..bf97bf35 100644
--- a/Sources/BSON/exports.swift
+++ b/Sources/BSON/exports.swift
@@ -1,2 +1,3 @@
-@_exported import BSONStreaming
-@_exported import BSONTypes
+@_exported import BSONABI
+@_exported import BSONDecoding
+@_exported import BSONEncoding
diff --git a/Sources/BSONTypes/BSON.swift b/Sources/BSONABI/BSON.AnyType.swift
similarity index 54%
rename from Sources/BSONTypes/BSON.swift
rename to Sources/BSONABI/BSON.AnyType.swift
index f8bde6e0..7282c4ef 100644
--- a/Sources/BSONTypes/BSON.swift
+++ b/Sources/BSONABI/BSON.AnyType.swift
@@ -1,34 +1,38 @@
-/// A BSON metatype. This enumeration also serves as a namespace for all
-/// other types in this module. The raw value of this enumeration is the
-/// type code of the associated case in BSON’s ABI.
-@frozen public
-enum BSON:UInt8
+extension BSON
{
- case double = 0x01
- case string = 0x02
- case document = 0x03
- case list = 0x04
- case binary = 0x05
-
- case id = 0x07
- case bool = 0x08
- case millisecond = 0x09
- case null = 0x0A
- case regex = 0x0B
- case pointer = 0x0C
- case javascript = 0x0D
+ /// A BSON metatype. The raw value of this enumeration is the type code of the associated
+ /// case in BSON’s ABI.
+ @frozen public
+ enum AnyType:UInt8, Equatable, Hashable, Sendable
+ {
+ case double = 0x01
+ case string = 0x02
+ case document = 0x03
+ case list = 0x04
+ case binary = 0x05
- case javascriptScope = 0x0F
- case int32 = 0x10
- case uint64 = 0x11
- case int64 = 0x12
- case decimal128 = 0x13
+ case id = 0x07
+ case bool = 0x08
+ case millisecond = 0x09
+ case null = 0x0A
+ case regex = 0x0B
+ case pointer = 0x0C
+ case javascript = 0x0D
- case min = 0xFF
- case max = 0x7F
+ case javascriptScope = 0x0F
+ case int32 = 0x10
+ case uint64 = 0x11
+ case int64 = 0x12
+ case decimal128 = 0x13
+ case min = 0xFF
+ case max = 0x7F
+ }
+}
+extension BSON.AnyType
+{
/// Calls ``init(rawValue:)``, but throws a ``TypeError`` instead of returning
- /// [`nil`]().
+ /// nil.
@inlinable public
init(code:UInt8) throws
{
@@ -38,7 +42,7 @@ enum BSON:UInt8
}
else
{
- throw TypeError.init(invalid: code)
+ throw BSON.TypeError.init(invalid: code)
}
}
/// Converts the given type code to a variant type. This function will canonicalize
@@ -75,3 +79,8 @@ enum BSON:UInt8
}
}
}
+extension BSON.AnyType:Comparable
+{
+ @inlinable public
+ static func < (a:Self, b:Self) -> Bool { a.rawValue < b.rawValue }
+}
diff --git a/Sources/BSONTypes/BSON.AnyValue.swift b/Sources/BSONABI/BSON.AnyValue.swift
similarity index 57%
rename from Sources/BSONTypes/BSON.AnyValue.swift
rename to Sources/BSONABI/BSON.AnyValue.swift
index c96d32bb..553cc152 100644
--- a/Sources/BSONTypes/BSON.AnyValue.swift
+++ b/Sources/BSONABI/BSON.AnyValue.swift
@@ -12,7 +12,8 @@ extension BSON
case binary(BSON.BinaryView
)
/// A boolean.
case bool(Bool)
- /// An [IEEE 754-2008 128-bit decimal](https://en.wikipedia.org/wiki/Decimal128_floating-point_format).
+ /// An [IEEE 754-2008 128-bit
+ /// decimal](https://en.wikipedia.org/wiki/Decimal128_floating-point_format).
case decimal128(BSON.Decimal128)
/// A double-precision float.
case double(Double)
@@ -25,8 +26,8 @@ extension BSON
/// Javascript code.
/// The payload is a library type to permit efficient document traversal.
case javascript(BSON.UTF8View)
- /// A javascript scope containing code. This variant is maintained for
- /// backward-compatibility with older versions of BSON and
+ /// 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)
/// The MongoDB max-key.
@@ -69,29 +70,29 @@ extension BSON.AnyValue
{
/// The type of this variant value.
@inlinable public
- var type:BSON
+ var type:BSON.AnyType
{
switch self
{
- case .document: return .document
- case .list: return .list
- case .binary: return .binary
- case .bool: return .bool
- case .decimal128: return .decimal128
- case .double: return .double
- case .id: return .id
- case .int32: return .int32
- case .int64: return .int64
- case .javascript: return .javascript
- case .javascriptScope: return .javascriptScope
- case .max: return .max
- case .millisecond: return .millisecond
- case .min: return .min
- case .null: return .null
- case .pointer: return .pointer
- case .regex: return .regex
- case .string: return .string
- case .uint64: return .uint64
+ case .document: .document
+ case .list: .list
+ case .binary: .binary
+ case .bool: .bool
+ case .decimal128: .decimal128
+ case .double: .double
+ case .id: .id
+ case .int32: .int32
+ case .int64: .int64
+ case .javascript: .javascript
+ case .javascriptScope: .javascriptScope
+ case .max: .max
+ case .millisecond: .millisecond
+ case .min: .min
+ case .null: .null
+ case .pointer: .pointer
+ case .regex: .regex
+ case .string: .string
+ case .uint64: .uint64
}
}
/// The size of this variant value when encoded.
@@ -101,63 +102,63 @@ extension BSON.AnyValue
switch self
{
case .document(let document):
- return document.size
+ document.size
case .list(let list):
- return list.size
+ list.size
case .binary(let binary):
- return binary.size
+ binary.size
case .bool:
- return 1
+ 1
case .decimal128:
- return 16
+ 16
case .double:
- return 8
+ 8
case .id:
- return 12
+ 12
case .int32:
- return 4
+ 4
case .int64:
- return 8
+ 8
case .javascript(let utf8):
- return utf8.size
+ utf8.size
case .javascriptScope(let scope, let utf8):
- return 4 + utf8.size + scope.size
+ 4 + utf8.size + scope.size
case .max:
- return 0
+ 0
case .millisecond:
- return 8
+ 8
case .min:
- return 0
+ 0
case .null:
- return 0
+ 0
case .pointer(let database, _):
- return 12 + database.size
+ 12 + database.size
case .regex(let regex):
- return regex.size
+ regex.size
case .string(let string):
- return string.size
+ string.size
case .uint64:
- return 8
+ 8
}
}
}
extension BSON.AnyValue
{
- /// Promotes a [`nil`]() result to a thrown ``TypecastError``.
- ///
+ /// Promotes a nil result to a thrown ``TypecastError``.
+ ///
/// If `T` conforms to ``BSONDecodable``, prefer calling its throwing
- /// ``BSONDecodable/.init(bson:)`` to calling this method directly.
+ /// ``BSONDecodable/init(bson:) [7O4O3]`` to calling this method directly.
///
- /// > Throws: A ``TypecastError`` if the given curried method returns [`nil`]().
+ /// > Throws: A ``TypecastError`` if the given curried method returns nil.
@inline(__always)
- @inlinable public
+ @inlinable public
func cast(with cast:(Self) throws -> T?) throws -> T
{
if let value:T = try cast(self)
{
- return value
+ return value
}
- else
+ else
{
throw BSON.TypecastError.init(invalid: self.type)
}
@@ -166,35 +167,35 @@ extension BSON.AnyValue
extension BSON.AnyValue
{
/// Attempts to load an instance of ``Bool`` from this variant.
- ///
+ ///
/// - Returns:
- /// The payload of this variant if it matches ``case bool(_:)``,
- /// [`nil`]() otherwise.
- @inlinable public
+ /// The payload of this variant if it matches ``bool(_:)``,
+ /// nil otherwise.
+ @inlinable public
func `as`(_:Bool.Type) -> Bool?
{
- switch self
+ switch self
{
- case .bool(let bool): return bool
- default: return nil
+ case .bool(let bool): bool
+ default: nil
}
}
/// Attempts to load an instance of some ``FixedWidthInteger`` from this variant.
- ///
+ ///
/// - Returns:
/// An integer derived from the payload of this variant
- /// if it matches one of ``case int32(_:)``, ``case int64(_:)``, or
- /// ``case uint64(_:)``, and it can be represented exactly by [`T`]();
- /// [`nil`]() otherwise.
+ /// if it matches one of ``int32(_:)``, ``int64(_:)``, or
+ /// ``uint64(_:)``, and it can be represented exactly by `T`;
+ /// nil otherwise.
///
- /// The ``case decimal128(_:)``, ``case double(_:)``, and ``case millisecond(_:)``
+ /// The ``decimal128(_:)``, ``double(_:)``, and ``millisecond(_:)``
/// variants will *not* match.
///
- /// This method reports failure in two ways — it returns [`nil`]() on a type
- /// mismatch, and it [`throws`]() an ``IntegerOverflowError`` if this variant
- /// was an integer, but it could not be represented exactly by [`T`]().
- @inlinable public
- func `as`(_:Integer.Type) throws -> Integer?
+ /// This method reports failure in two ways — it returns nil on a type
+ /// mismatch, and it throws an ``IntegerOverflowError`` if this variant
+ /// was an integer, but it could not be represented exactly by `T`.
+ @inlinable public
+ func `as`(_:Integer.Type) throws -> Integer?
where Integer:FixedWidthInteger
{
switch self
@@ -232,95 +233,95 @@ extension BSON.AnyValue
}
/// Attempts to load an instance of some ``BinaryFloatingPoint`` type from
/// this variant.
- ///
+ ///
/// - Returns:
- /// The closest value of [`T`]() to the payload of this
- /// variant if it matches ``case double(_:)``, [`nil`]() otherwise.
- @inlinable public
+ /// The closest value of `T` to the payload of this
+ /// variant if it matches ``double(_:)``, nil otherwise.
+ @inlinable public
func `as`(_:Fraction.Type) -> Fraction?
where Fraction:BinaryFloatingPoint
{
- switch self
+ switch self
{
case .double(let double): return .init(double)
- default: return nil
+ default: return nil
}
}
/// Attempts to load an instance of ``Decimal128`` from this variant.
- ///
+ ///
/// - Returns:
- /// The payload of this variant if it matches ``case decimal128(_:)``,
- /// [`nil`]() otherwise.
- @inlinable public
+ /// The payload of this variant if it matches ``decimal128(_:)``,
+ /// nil otherwise.
+ @inlinable public
func `as`(_:BSON.Decimal128.Type) -> BSON.Decimal128?
{
- switch self
+ switch self
{
- case .decimal128(let decimal): return decimal
- default: return nil
+ case .decimal128(let decimal): decimal
+ default: nil
}
}
/// Attempts to load an instance of ``Identifier`` from this variant.
- ///
+ ///
/// - Returns:
- /// The payload of this variant if it matches ``case id(_:)`` or
- /// ``case pointer(_:_:)``, [`nil`]() otherwise.
- @inlinable public
+ /// The payload of this variant if it matches ``id(_:)`` or
+ /// ``pointer(_:_:)``, nil otherwise.
+ @inlinable public
func `as`(_:BSON.Identifier.Type) -> BSON.Identifier?
{
- switch self
+ switch self
{
case .id(let id):
- return id
+ id
case .pointer(_, let id):
- return id
+ id
default:
- return nil
+ nil
}
}
/// Attempts to load an instance of ``Millisecond`` from this variant.
- ///
+ ///
/// - Returns:
- /// The payload of this variant if it matches ``case millisecond(_:)``,
- /// [`nil`]() otherwise.
- @inlinable public
+ /// The payload of this variant if it matches ``millisecond(_:)``,
+ /// nil otherwise.
+ @inlinable public
func `as`(_:BSON.Millisecond.Type) -> BSON.Millisecond?
{
- switch self
+ switch self
{
case .millisecond(let millisecond):
- return millisecond
+ millisecond
default:
- return nil
+ nil
}
}
/// Attempts to load an instance of ``Regex`` from this variant.
- ///
+ ///
/// - Returns:
- /// The payload of this variant if it matches ``case regex(_:)``,
- /// [`nil`]() otherwise.
- @inlinable public
+ /// The payload of this variant if it matches ``regex(_:)``,
+ /// nil otherwise.
+ @inlinable public
func `as`(_:BSON.Regex.Type) -> BSON.Regex?
{
- switch self
+ switch self
{
case .regex(let regex):
- return regex
+ regex
default:
- return nil
+ nil
}
}
/// Attempts to load an instance of ``String`` from this variant.
/// Its UTF-8 code units will be validated (and repaired if needed).
- ///
+ ///
/// - Returns:
/// The payload of this variant, decoded to a ``String``, if it matches
- /// either ``case string(_:)`` or ``case javascript(_:)``, [`nil`]()
+ /// either ``string(_:)`` or ``javascript(_:)``, nil
/// otherwise.
///
- /// > Complexity:
+ /// > Complexity:
/// O(*n*), where *n* is the length of the string.
- @inlinable public
+ @inlinable public
func `as`(_:String.Type) -> String?
{
self.utf8.map(String.init(bson:))
@@ -329,121 +330,186 @@ extension BSON.AnyValue
extension BSON.AnyValue
{
/// Attempts to load an explicit ``null`` from this variant.
- ///
+ ///
/// - Returns:
- /// [`nil`]() in the inner optional this variant is ``null``,
- // [`nil`]() in the outer optional otherwise.
- @inlinable public
+ /// nil in the inner optional this variant is ``null``,
+ // nil in the outer optional otherwise.
+ @inlinable public
func `as`(_:Never?.Type) -> Never??
{
- switch self
+ switch self
{
- case .null: return (nil as Never?) as Never??
- default: return nil as Never??
+ case .null: (nil as Never?) as Never??
+ default: nil as Never??
}
}
/// Attempts to load a ``max`` key from this variant.
- ///
+ ///
/// - Returns:
- /// ``Max.max`` if this variant is ``max``, [`nil`]() otherwise.
- @inlinable public
+ /// A (the) instance of ``Max`` if this variant is ``max``, nil otherwise.
+ @inlinable public
func `as`(_:BSON.Max.Type) -> BSON.Max?
{
- switch self
+ switch self
{
- case .max: return .init()
- default: return nil
+ case .max: .init()
+ default: nil
}
}
/// Attempts to load a ``min`` key from this variant.
- ///
+ ///
/// - Returns:
- /// ``Min.min`` if this variant is ``min``, [`nil`]() otherwise.
- @inlinable public
+ /// A (the) instance of ``min`` if this variant is ``min``, nil otherwise.
+ @inlinable public
func `as`(_:BSON.Min.Type) -> BSON.Min?
{
- switch self
+ switch self
{
- case .min: return .init()
- default: return nil
+ case .min: .init()
+ default: nil
}
}
}
extension BSON.AnyValue
{
/// Attempts to unwrap a binary array from this variant.
- ///
- /// - Returns: The payload of this variant if it matches ``case binary(_:)``,
- /// [`nil`]() otherwise.
- ///
+ ///
+ /// - Returns: The payload of this variant if it matches ``binary(_:)``,
+ /// nil otherwise.
+ ///
/// > Complexity: O(1).
- @inlinable public
+ @inlinable public
var binary:BSON.BinaryView?
{
- switch self
+ switch self
{
case .binary(let binary):
- return binary
+ binary
default:
- return nil
+ nil
}
}
/// Attempts to unwrap a document from this variant.
- ///
- /// - Returns: The payload of this variant if it matches ``case document(_:)``
- /// or ``case list(_:)``, [`nil`]() otherwise.
- ///
+ ///
+ /// - Returns: The payload of this variant if it matches ``document(_:)``
+ /// **or** ``list(_:)``, nil otherwise.
+ ///
/// If the variant was a list, the string keys of the returned document are likely
/// (but not guaranteed) to be the list indices encoded as base-10 strings, without
/// leading zeros.
- ///
+ ///
/// > Complexity: O(1).
- @inlinable public
+ @inlinable public
var document:BSON.DocumentView?
{
- switch self
+ switch self
{
case .document(let document):
- return document
+ document
case .list(let list):
- return list.document
+ list.document
default:
- return nil
+ nil
}
}
/// Attempts to unwrap a list from this variant.
- ///
+ ///
/// - Returns:
- /// The payload of this variant if it matches ``case list(_:)``,
- /// [`nil`]() otherwise.
+ /// The payload of this variant if it matches ``list(_:)``,
+ /// nil otherwise.
///
/// > Complexity: O(1).
- @inlinable public
+ @inlinable public
var list:BSON.ListView?
{
- switch self
+ switch self
{
- case .list(let list): return list
- default: return nil
+ case .list(let list): list
+ default: nil
}
}
/// Attempts to unwrap an instance of ``UTF8View`` from this variant. Its UTF-8
/// code units will *not* be validated, which allowes this method to return
/// in constant time.
- ///
+ ///
/// - Returns:
- /// The payload of this variant if it matches either ``case string(_:)``
- /// or ``case javascript(_:)``, [`nil`]() otherwise.
+ /// The payload of this variant if it matches either ``string(_:)``
+ /// or ``javascript(_:)``, nil otherwise.
///
/// > Complexity: O(1).
- @inlinable public
+ @inlinable public
var utf8:BSON.UTF8View?
{
- switch self
+ switch self
{
- case .javascript(let code): return code
- case .string(let code): return code
- default: return nil
+ case .javascript(let code): code
+ case .string(let code): code
+ default: nil
}
}
}
+
+extension BSON.AnyValue:ExpressibleByStringLiteral,
+ ExpressibleByArrayLiteral,
+ ExpressibleByExtendedGraphemeClusterLiteral,
+ ExpressibleByUnicodeScalarLiteral,
+ ExpressibleByDictionaryLiteral
+ where Bytes:RangeReplaceableCollection,
+ Bytes:RandomAccessCollection,
+ Bytes.Index == Int
+{
+ @inlinable public
+ init(stringLiteral:String)
+ {
+ self = .string(.init(from: stringLiteral))
+ }
+ @inlinable public
+ init(arrayLiteral:Self...)
+ {
+ self = .list(.init(elements: arrayLiteral))
+ }
+ @inlinable public
+ init(dictionaryLiteral:(BSON.Key, Self)...)
+ {
+ self = .document(.init(fields: dictionaryLiteral))
+ }
+}
+
+extension BSON.AnyValue:ExpressibleByFloatLiteral
+{
+ @inlinable public
+ init(floatLiteral:Double)
+ {
+ self = .double(floatLiteral)
+ }
+}
+extension BSON.AnyValue:ExpressibleByIntegerLiteral
+{
+ /// Creates an instance initialized to the specified integer value.
+ /// It will be an ``int32(_:)`` value if it fits, otherwise it will
+ /// be an ``int64(_:)``.
+ ///
+ /// Although MongoDB uses ``Int32`` as its default integer type,
+ /// this library infers integer literals to be of type ``Int`` for
+ /// consistency with the rest of the Swift language.
+ @inlinable public
+ init(integerLiteral:Int)
+ {
+ if let int32:Int32 = .init(exactly: integerLiteral)
+ {
+ self = .int32(int32)
+ }
+ else
+ {
+ self = .int64(Int64.init(integerLiteral))
+ }
+ }
+}
+extension BSON.AnyValue:ExpressibleByBooleanLiteral
+{
+ @inlinable public
+ init(booleanLiteral:Bool)
+ {
+ self = .bool(booleanLiteral)
+ }
+}
diff --git a/Sources/BSONABI/BSON.Decoder.swift b/Sources/BSONABI/BSON.Decoder.swift
new file mode 100644
index 00000000..e7313fe4
--- /dev/null
+++ b/Sources/BSONABI/BSON.Decoder.swift
@@ -0,0 +1,22 @@
+extension BSON
+{
+ public
+ typealias Decoder = _BSONDecoder
+}
+
+/// The name of this protocol is ``BSON.Decoder``.
+public
+protocol _BSONDecoder
+{
+ associatedtype Storage:RandomAccessCollection
+
+ init(parsing bson:__shared BSON.AnyValue) throws
+}
+
+extension BSON.Decoder
+{
+ /// Decoder elements are indices over fragments of BSON parsed from a larger allocation,
+ /// like ``Substring``s from a larger parent ``String``.
+ public
+ typealias Bytes = Storage.SubSequence
+}
diff --git a/Sources/BSONABI/BSON.Encoder.swift b/Sources/BSONABI/BSON.Encoder.swift
new file mode 100644
index 00000000..ffc4c7b1
--- /dev/null
+++ b/Sources/BSONABI/BSON.Encoder.swift
@@ -0,0 +1,18 @@
+extension BSON
+{
+ public
+ typealias Encoder = _BSONEncoder
+}
+
+/// The name of this protocol is ``BSON.Encoder``.
+public
+protocol _BSONEncoder
+{
+ init(_:consuming BSON.Output<[UInt8]>)
+
+ consuming
+ func move() -> BSON.Output<[UInt8]>
+
+ static
+ var type:BSON.AnyType { get }
+}
diff --git a/Sources/BSONTypes/BSON.TypeError.swift b/Sources/BSONABI/BSON.TypeError.swift
similarity index 100%
rename from Sources/BSONTypes/BSON.TypeError.swift
rename to Sources/BSONABI/BSON.TypeError.swift
diff --git a/Sources/BSONTypes/BSON.TypecastError.swift b/Sources/BSONABI/BSON.TypecastError.swift
similarity index 78%
rename from Sources/BSONTypes/BSON.TypecastError.swift
rename to Sources/BSONABI/BSON.TypecastError.swift
index 4d4c2663..108c8eea 100644
--- a/Sources/BSONTypes/BSON.TypecastError.swift
+++ b/Sources/BSONABI/BSON.TypecastError.swift
@@ -1,14 +1,14 @@
extension BSON
{
/// A decoder failed to cast a variant to an expected value type.
- @frozen public
+ @frozen public
struct TypecastError:Equatable, Error
{
public
- let variant:BSON
+ let variant:AnyType
@inlinable public
- init(invalid variant:BSON)
+ init(invalid variant:AnyType)
{
self.variant = variant
}
@@ -17,7 +17,7 @@ extension BSON
extension BSON.TypecastError:CustomStringConvertible
{
public
- var description:String
+ var description:String
{
"cannot cast variant of type '\(self.variant)' to type '\(Value.self)'"
}
diff --git a/Sources/BSONABI/BSON.swift b/Sources/BSONABI/BSON.swift
new file mode 100644
index 00000000..35da0206
--- /dev/null
+++ b/Sources/BSONABI/BSON.swift
@@ -0,0 +1,5 @@
+/// The namespace for all BSON types.
+@frozen public
+enum BSON
+{
+}
diff --git a/Sources/BSONStreaming/BSONRepresentable.swift b/Sources/BSONABI/BSONRepresentable.swift
similarity index 90%
rename from Sources/BSONStreaming/BSONRepresentable.swift
rename to Sources/BSONABI/BSONRepresentable.swift
index a095b83a..b84ea8f8 100644
--- a/Sources/BSONStreaming/BSONRepresentable.swift
+++ b/Sources/BSONABI/BSONRepresentable.swift
@@ -1,5 +1,3 @@
-import BSONTypes
-
public
protocol BSONRepresentable
{
diff --git a/Sources/BSONStreaming/BSON.Field.swift b/Sources/BSONABI/Fields/BSON.FieldEncoder.swift
similarity index 91%
rename from Sources/BSONStreaming/BSON.Field.swift
rename to Sources/BSONABI/Fields/BSON.FieldEncoder.swift
index 664596a4..833b473d 100644
--- a/Sources/BSONStreaming/BSON.Field.swift
+++ b/Sources/BSONABI/Fields/BSON.FieldEncoder.swift
@@ -1,11 +1,14 @@
-import BSONTypes
-import BSONTraversal
-
+extension BSON
+{
+ @available(*, deprecated, renamed: "FieldEncoder")
+ public
+ typealias Field = BSON.FieldEncoder
+}
extension BSON
{
/// A type that can serialize any BSON container element.
@frozen public
- struct Field
+ struct FieldEncoder
{
public
let key:Key
@@ -20,7 +23,7 @@ extension BSON
}
}
}
-extension BSON.Field
+extension BSON.FieldEncoder
{
@inlinable public mutating
func encode(double:Double)
@@ -117,10 +120,10 @@ extension BSON.Field
self[.javascript].serialize(utf8: javascript)
}
}
-extension BSON.Field
+extension BSON.FieldEncoder
{
@inlinable internal
- subscript(type:BSON) -> Void
+ subscript(type:BSON.AnyType) -> Void
{
mutating get
{
@@ -129,7 +132,7 @@ extension BSON.Field
}
}
@inlinable internal
- subscript(type:BSON) -> BSON.Output<[UInt8]>
+ subscript(type:BSON.AnyType) -> BSON.Output<[UInt8]>
{
mutating get
{
@@ -143,14 +146,14 @@ extension BSON.Field
}
}
}
-extension BSON.Field
+extension BSON.FieldEncoder
{
/// Writes the stored type code and ``key`` to the output buffer, temporarily rebinds
/// the output’s storage buffer to an encoder of the specified type, and brackets any
/// newly-written bytes with the appropriate headers or trailers, if performing a
/// mutation. The getter has no effect.
@inlinable public
- subscript(as _:Encoder.Type = Encoder.self) -> Encoder where Encoder:BSONEncoder
+ subscript(as _:Encoder.Type = Encoder.self) -> Encoder where Encoder:BSON.Encoder
{
get
{
diff --git a/Sources/BSONTypes/BSON.Key.swift b/Sources/BSONABI/Fields/BSON.Key.swift
similarity index 100%
rename from Sources/BSONTypes/BSON.Key.swift
rename to Sources/BSONABI/Fields/BSON.Key.swift
diff --git a/Sources/BSONTraversal/VariableLengthBSON.swift b/Sources/BSONABI/IO/BSON.FrameTraversable.swift
similarity index 60%
rename from Sources/BSONTraversal/VariableLengthBSON.swift
rename to Sources/BSONABI/IO/BSON.FrameTraversable.swift
index 11029e2e..0c82392c 100644
--- a/Sources/BSONTraversal/VariableLengthBSON.swift
+++ b/Sources/BSONABI/IO/BSON.FrameTraversable.swift
@@ -1,20 +1,26 @@
-/// A BSON view that parsers can traverse in constant time.
-///
-/// BSON parsers typically parse conforming types by reading a length
-/// header from raw input data, and using it to slice the input,
-/// ideally without copying backing storage. The interpretation of the
-/// length header is specified by the ``Frame`` type requirement, and
-/// the exact slicing behavior is determined by the implementation’s
-/// ``init(slicing:)`` witness.
+extension BSON
+{
+ /// A framed type that BSON parsers can traverse in constant time.
+ ///
+ /// BSON parsers typically parse conforming types by reading a length
+ /// header from raw input data, and using it to slice the input,
+ /// ideally without copying backing storage. The interpretation of the
+ /// length header is specified by the ``FrameTraversable/Frame`` type requirement, and
+ /// the exact slicing behavior is determined by the implementation’s
+ /// ``init(slicing:)`` witness.
+ public
+ typealias FrameTraversable = _BSONFrameTraversable
+}
+
public
-protocol VariableLengthBSON
+protocol _BSONFrameTraversable
{
/// The backing storage used by this type. I recommend satisfying
/// this with generics, to avoid copying input data.
associatedtype Bytes:RandomAccessCollection
/// The type specifying how parsers should interpret the conforming
/// type’s inline frame header when it appears in raw input data.
- associatedtype Frame:VariableLengthBSONFrame
+ associatedtype Frame:BSON.FrameType
/// Receives a collection of bytes encompassing the bytes backing
/// this value, after stripping the length header and frame suffix,
diff --git a/Sources/BSONTraversal/VariableLengthBSONFrame.swift b/Sources/BSONABI/IO/BSON.FrameType.swift
similarity index 61%
rename from Sources/BSONTraversal/VariableLengthBSONFrame.swift
rename to Sources/BSONABI/IO/BSON.FrameType.swift
index 6eaf391f..b99c0c85 100644
--- a/Sources/BSONTraversal/VariableLengthBSONFrame.swift
+++ b/Sources/BSONABI/IO/BSON.FrameType.swift
@@ -1,8 +1,15 @@
-/// A type that specifies the layout of a variable-length BSON view.
-/// Parsers use conforming types to decide how to interpret BSON
-/// length headers read from input data.
+extension BSON
+{
+ /// A type that specifies the layout of a variable-length BSON view.
+ /// Parsers use conforming types to decide how to interpret BSON
+ /// length headers read from input data.
+ public
+ typealias FrameType = _BSONFrameType
+}
+
+/// The name of this protocol is ``BSON.FrameType``.
public
-protocol VariableLengthBSONFrame
+protocol _BSONFrameType
{
/// The number of (conceptual) bytes in the frame prefix of the type
/// this frame type is associated with.
@@ -16,18 +23,19 @@ protocol VariableLengthBSONFrame
static
var trailer:UInt8? { get }
}
-extension VariableLengthBSONFrame
+
+extension BSON.FrameType
{
/// The number of (conceptual) bytes in the frame suffix of the type
/// this frame type is associated with. This is 0 if ``trailer`` is
/// nil, and 1 otherwise.
- @inlinable public static
+ @inlinable internal static
var suffix:Int
{
switch self.trailer
{
- case nil: return 0
- case _?: return 1
+ case nil: 0
+ case _?: 1
}
}
}
diff --git a/Sources/BSONABI/IO/BSON.FrameView.swift b/Sources/BSONABI/IO/BSON.FrameView.swift
new file mode 100644
index 00000000..79279971
--- /dev/null
+++ b/Sources/BSONABI/IO/BSON.FrameView.swift
@@ -0,0 +1,20 @@
+extension BSON
+{
+ /// A type that can be (efficiently) decoded from a BSON variant value
+ /// backed by a preferred type of storage particular to the decoded type.
+ ///
+ /// This protocol is parallel and unrelated to ``BSONDecodable`` to
+ /// emphasize the performance characteristics of types that conform to
+ /// this protocol and not ``BSONDecodable``.
+ public
+ typealias FrameView = _BSONFrameView
+}
+
+/// The name of this protocol is ``BSON.FrameView``.
+public
+protocol _BSONFrameView:BSON.FrameTraversable, Equatable
+{
+ /// Attempts to cast a BSON variant backed by ``Bytes`` to an instance
+ /// of this view type without copying the contents of the backing storage.
+ init(_:BSON.AnyValue) throws
+}
diff --git a/Sources/BSONTypes/BSON.HeaderError.swift b/Sources/BSONABI/IO/BSON.HeaderError.swift
similarity index 76%
rename from Sources/BSONTypes/BSON.HeaderError.swift
rename to Sources/BSONABI/IO/BSON.HeaderError.swift
index 2ad21366..4f0e235f 100644
--- a/Sources/BSONTypes/BSON.HeaderError.swift
+++ b/Sources/BSONABI/IO/BSON.HeaderError.swift
@@ -1,14 +1,12 @@
-import BSONTraversal
-
extension BSON
{
- public
- struct HeaderError:Equatable, Error where Frame:VariableLengthBSONFrame
+ @frozen public
+ struct HeaderError:Equatable, Error where Frame:FrameType
{
public
let length:Int
- public
+ @inlinable public
init(length:Int)
{
self.length = length
diff --git a/Sources/BSONStreaming/BSON.Input.swift b/Sources/BSONABI/IO/BSON.Input.swift
similarity index 97%
rename from Sources/BSONStreaming/BSON.Input.swift
rename to Sources/BSONABI/IO/BSON.Input.swift
index 2db18442..61e02d45 100644
--- a/Sources/BSONStreaming/BSON.Input.swift
+++ b/Sources/BSONABI/IO/BSON.Input.swift
@@ -1,6 +1,3 @@
-import BSONTraversal
-import BSONTypes
-
extension BSON
{
/// A type for managing BSON parsing state. Most users of this module
@@ -153,7 +150,7 @@ extension BSON.Input
@inlinable public mutating
func parse(_:Frame.Type) throws -> Source.SubSequence
- where Frame:VariableLengthBSONFrame
+ where Frame:BSON.FrameType
{
let header:Int = .init(try self.parse(as: Int32.self))
let stride:Int = header + Frame.skipped
@@ -179,7 +176,7 @@ extension BSON.Input
/// which allows decoders to skip over regions of a BSON document.
@inlinable public mutating
func parse(as _:View.Type = View.self) throws -> View
- where View:VariableLengthBSON
+ where View:BSON.FrameTraversable
{
try .init(slicing: try self.parse(View.Frame.self))
}
@@ -216,7 +213,7 @@ extension BSON.Input
{
/// Parses a variant BSON value, assuming it is of the specified `variant` type.
@inlinable public mutating
- func parse(variant:BSON) throws -> BSON.AnyValue
+ func parse(variant:BSON.AnyType) throws -> BSON.AnyValue
{
switch variant
{
diff --git a/Sources/BSONStreaming/BSON.InputError.Expectation.swift b/Sources/BSONABI/IO/BSON.InputError.Expectation.swift
similarity index 81%
rename from Sources/BSONStreaming/BSON.InputError.Expectation.swift
rename to Sources/BSONABI/IO/BSON.InputError.Expectation.swift
index 8bd8dda1..09702b77 100644
--- a/Sources/BSONStreaming/BSON.InputError.Expectation.swift
+++ b/Sources/BSONABI/IO/BSON.InputError.Expectation.swift
@@ -1,5 +1,3 @@
-import BSONTypes
-
extension BSON.InputError
{
@frozen public
@@ -21,11 +19,11 @@ extension BSON.InputError.Expectation:CustomStringConvertible
switch self
{
case .end:
- return "end-of-input"
+ "end-of-input"
case .byte(let byte):
- return "terminator byte (\(byte))"
+ "terminator byte (\(byte))"
case .bytes(let count):
- return "\(count) byte(s)"
+ "\(count) byte(s)"
}
}
}
diff --git a/Sources/BSONStreaming/BSON.InputError.swift b/Sources/BSONABI/IO/BSON.InputError.swift
similarity index 97%
rename from Sources/BSONStreaming/BSON.InputError.swift
rename to Sources/BSONABI/IO/BSON.InputError.swift
index e75a68c6..7c1c9244 100644
--- a/Sources/BSONStreaming/BSON.InputError.swift
+++ b/Sources/BSONABI/IO/BSON.InputError.swift
@@ -1,5 +1,3 @@
-import BSONTypes
-
extension BSON
{
/// A parser did not receive the expected amount of input.
diff --git a/Sources/BSONStreaming/BSON.Output.swift b/Sources/BSONABI/IO/BSON.Output.swift
similarity index 95%
rename from Sources/BSONStreaming/BSON.Output.swift
rename to Sources/BSONABI/IO/BSON.Output.swift
index ec3fd5a4..69c63396 100644
--- a/Sources/BSONStreaming/BSON.Output.swift
+++ b/Sources/BSONABI/IO/BSON.Output.swift
@@ -1,6 +1,3 @@
-import BSONTypes
-import BSONTraversal
-
extension BSON
{
@frozen public
@@ -24,7 +21,8 @@ extension BSON
/// number of bytes in the destination buffer.
///
/// The size hint is only effective if `Destination` provides a real,
- /// non-defaulted witness for ``RangeReplaceableCollection.reserveCapacity(_:)``.
+ /// non-defaulted witness for
+ /// ``RangeReplaceableCollection.reserveCapacity(_:) [2YKV1]``.
@inlinable public
init(capacity:Int)
{
@@ -54,7 +52,7 @@ extension BSON.Output
extension BSON.Output
{
@inlinable public mutating
- func serialize(type:BSON)
+ func serialize(type:BSON.AnyType)
{
self.append(type.rawValue)
}
@@ -213,7 +211,7 @@ extension BSON.Output<[UInt8]>
/// - See also: ``subscript(as:)``.
@inlinable public
subscript(as _:Encoder.Type, in frame:BSON.DocumentFrame.Type) -> Encoder
- where Encoder:BSONEncoder
+ where Encoder:BSON.Encoder
{
get
{
@@ -230,7 +228,7 @@ extension BSON.Output<[UInt8]>
///
/// - See also: ``subscript(with:)``.
@inlinable public
- subscript(as _:Encoder.Type) -> Encoder where Encoder:BSONEncoder
+ subscript(as _:Encoder.Type) -> Encoder where Encoder:BSON.Encoder
{
_read
{
@@ -245,7 +243,7 @@ extension BSON.Output<[UInt8]>
}
}
@inlinable public
- subscript(with key:BSON.Key) -> BSON.Field
+ subscript(with key:BSON.Key) -> BSON.FieldEncoder
{
get
{
@@ -253,14 +251,14 @@ extension BSON.Output<[UInt8]>
}
_modify
{
- var field:BSON.Field = self[with: key]
+ var field:BSON.FieldEncoder = self[with: key]
self = .init(preallocated: [])
defer { self = field.output }
yield &field
}
}
@inlinable internal
- subscript(in frame:(some VariableLengthBSONFrame).Type) -> Self
+ subscript(in frame:(some BSON.FrameType).Type) -> Self
{
get
{
diff --git a/Sources/BSONTraversal/BufferSlice.swift b/Sources/BSONABI/IO/BufferSlice.swift
similarity index 100%
rename from Sources/BSONTraversal/BufferSlice.swift
rename to Sources/BSONABI/IO/BufferSlice.swift
diff --git a/Sources/BSONTypes/BSON.BooleanSubtypeError.swift b/Sources/BSONABI/Primitives/BSON.BooleanSubtypeError.swift
similarity index 100%
rename from Sources/BSONTypes/BSON.BooleanSubtypeError.swift
rename to Sources/BSONABI/Primitives/BSON.BooleanSubtypeError.swift
diff --git a/Sources/BSONTypes/BSON.Decimal128.swift b/Sources/BSONABI/Primitives/BSON.Decimal128.swift
similarity index 91%
rename from Sources/BSONTypes/BSON.Decimal128.swift
rename to Sources/BSONABI/Primitives/BSON.Decimal128.swift
index e119afbb..972272e5 100644
--- a/Sources/BSONTypes/BSON.Decimal128.swift
+++ b/Sources/BSONABI/Primitives/BSON.Decimal128.swift
@@ -8,15 +8,15 @@ extension BSON
///
/// Take caution when using this type’s ``Hashable`` and ``Equatable`` conformances.
/// Two `Decimal128` values can encode the same numeric value, yet compare unequal
- /// under ``Equatable/.==(_:_:)``.
+ /// under ``Equatable.==(_:_:)``.
@frozen public
struct Decimal128:Hashable, Equatable, Sendable
{
/// The low 64 bits of this decimal value.
- public
+ public
var low:UInt64
/// The high 64 bits of this decimal value.
- public
+ public
var high:UInt64
@inlinable public
diff --git a/Sources/BSONStreaming/BSON.Document.swift b/Sources/BSONABI/Primitives/BSON.Document.swift
similarity index 96%
rename from Sources/BSONStreaming/BSON.Document.swift
rename to Sources/BSONABI/Primitives/BSON.Document.swift
index 8fcaa61e..3887a94a 100644
--- a/Sources/BSONStreaming/BSON.Document.swift
+++ b/Sources/BSONABI/Primitives/BSON.Document.swift
@@ -1,5 +1,3 @@
-import BSONTypes
-
extension BSON
{
/// The `Document` type models the “universal” BSON DSL.
@@ -82,7 +80,7 @@ extension BSON.Document
self.output.append(other.bytes)
}
@inlinable public mutating
- func append(_ key:String, with encode:(inout BSON.Field) -> ())
+ func append(_ key:String, with encode:(inout BSON.FieldEncoder) -> ())
{
encode(&self.output[with: .init(rawValue: key)])
}
diff --git a/Sources/BSONTypes/BSON.Identifier.swift b/Sources/BSONABI/Primitives/BSON.Identifier.swift
similarity index 100%
rename from Sources/BSONTypes/BSON.Identifier.swift
rename to Sources/BSONABI/Primitives/BSON.Identifier.swift
diff --git a/Sources/BSONTypes/BSON.IntegerOverflowError.swift b/Sources/BSONABI/Primitives/BSON.IntegerOverflowError.swift
similarity index 74%
rename from Sources/BSONTypes/BSON.IntegerOverflowError.swift
rename to Sources/BSONABI/Primitives/BSON.IntegerOverflowError.swift
index 0bea0c5a..d90fce4b 100644
--- a/Sources/BSONTypes/BSON.IntegerOverflowError.swift
+++ b/Sources/BSONABI/Primitives/BSON.IntegerOverflowError.swift
@@ -23,11 +23,11 @@ extension BSON.IntegerOverflowError:CustomStringConvertible
switch self
{
case .int32 (let value):
- return "value '\(value)' of type 'int32' overflows decoded type '\(Overflowed.self)'"
+ "value '\(value)' of type 'int32' overflows decoded type '\(Overflowed.self)'"
case .int64 (let value):
- return "value '\(value)' of type 'int64' overflows decoded type '\(Overflowed.self)'"
+ "value '\(value)' of type 'int64' overflows decoded type '\(Overflowed.self)'"
case .uint64(let value):
- return "value '\(value)' of type 'uint64' overflows decoded type '\(Overflowed.self)'"
+ "value '\(value)' of type 'uint64' overflows decoded type '\(Overflowed.self)'"
}
}
}
diff --git a/Sources/BSONStreaming/BSON.List.swift b/Sources/BSONABI/Primitives/BSON.List.swift
similarity index 98%
rename from Sources/BSONStreaming/BSON.List.swift
rename to Sources/BSONABI/Primitives/BSON.List.swift
index 67093cde..be275024 100644
--- a/Sources/BSONStreaming/BSON.List.swift
+++ b/Sources/BSONABI/Primitives/BSON.List.swift
@@ -1,5 +1,3 @@
-import BSONTypes
-
extension BSON
{
@frozen public
diff --git a/Sources/BSONTypes/BSON.Max.swift b/Sources/BSONABI/Primitives/BSON.Max.swift
similarity index 100%
rename from Sources/BSONTypes/BSON.Max.swift
rename to Sources/BSONABI/Primitives/BSON.Max.swift
diff --git a/Sources/BSONTypes/BSON.Millisecond.swift b/Sources/BSONABI/Primitives/BSON.Millisecond.swift
similarity index 100%
rename from Sources/BSONTypes/BSON.Millisecond.swift
rename to Sources/BSONABI/Primitives/BSON.Millisecond.swift
diff --git a/Sources/BSONTypes/BSON.Min.swift b/Sources/BSONABI/Primitives/BSON.Min.swift
similarity index 100%
rename from Sources/BSONTypes/BSON.Min.swift
rename to Sources/BSONABI/Primitives/BSON.Min.swift
diff --git a/Sources/BSONTypes/BSON.Regex.OptionError.swift b/Sources/BSONABI/Primitives/BSON.Regex.OptionError.swift
similarity index 100%
rename from Sources/BSONTypes/BSON.Regex.OptionError.swift
rename to Sources/BSONABI/Primitives/BSON.Regex.OptionError.swift
diff --git a/Sources/BSONTypes/BSON.Regex.Options.swift b/Sources/BSONABI/Primitives/BSON.Regex.Options.swift
similarity index 94%
rename from Sources/BSONTypes/BSON.Regex.Options.swift
rename to Sources/BSONABI/Primitives/BSON.Regex.Options.swift
index 6f96e7fb..53633767 100644
--- a/Sources/BSONTypes/BSON.Regex.Options.swift
+++ b/Sources/BSONABI/Primitives/BSON.Regex.Options.swift
@@ -59,12 +59,12 @@ extension BSON.Regex.Option
{
switch self
{
- case .i: return "i"
- case .l: return "l"
- case .m: return "m"
- case .s: return "s"
- case .u: return "u"
- case .x: return "x"
+ case .i: "i"
+ case .l: "l"
+ case .m: "m"
+ case .s: "s"
+ case .u: "u"
+ case .x: "x"
}
}
@inlinable public
diff --git a/Sources/BSONTypes/BSON.Regex.swift b/Sources/BSONABI/Primitives/BSON.Regex.swift
similarity index 100%
rename from Sources/BSONTypes/BSON.Regex.swift
rename to Sources/BSONABI/Primitives/BSON.Regex.swift
diff --git a/Sources/BSONABI/README.md b/Sources/BSONABI/README.md
new file mode 100644
index 00000000..ea369640
--- /dev/null
+++ b/Sources/BSONABI/README.md
@@ -0,0 +1,66 @@
+# ``/BSONABI``
+
+Models the BSON type system and the binary interface of the BSON serialization format.
+
+External users should avoid importing this module directly. Instead, import ``/BSON``.
+
+## Topics
+
+### Type system
+
+- ``BSON.AnyValue``
+- ``BSON.AnyType``
+
+### Primitive types
+
+- ``BSON.Min``
+- ``BSON.Max``
+- ``BSON.Identifier``
+- ``BSON.Millisecond``
+- ``BSON.Decimal128``
+- ``BSON.Regex``
+
+### String-like types
+
+- ``BSON.BinaryView``
+- ``BSON.UTF8View``
+
+### Container types
+
+- ``BSON.List``
+- ``BSON.ListView``
+- ``BSON.Document``
+- ``BSON.DocumentView``
+
+### Container fields
+
+- ``BSON.Key``
+- ``BSON.FieldEncoder``
+
+### Binary interface
+
+- ``BSON.FrameTraversable``
+- ``BSON.FrameType``
+- ``BSON.FrameView``
+
+### Binary frame types
+
+- ``BSON.BinaryFrame``
+- ``BSON.DocumentFrame``
+- ``BSON.UTF8Frame``
+
+### Parsing and decoding
+
+This module only implements the basic infrastructure for BSON decoding. Most of the public decoding interface is in ``BSONDecoding``.
+
+- ``BSON.Decoder``
+- ``BSON.Input``
+- ``BSON.TypeError``
+- ``BSON.TypecastError``
+
+### Serialization and encoding
+
+This module only implements the basic infrastructure for BSON encoding. Most of the public encoding interface is in ``BSONEncoding``.
+
+- ``BSON.Encoder``
+- ``BSON.Output``
diff --git a/Sources/BSONTypes/BSON.BinaryFrame.swift b/Sources/BSONABI/Views/BSON.BinaryFrame.swift
similarity index 84%
rename from Sources/BSONTypes/BSON.BinaryFrame.swift
rename to Sources/BSONABI/Views/BSON.BinaryFrame.swift
index 2abb3488..190c70e6 100644
--- a/Sources/BSONTypes/BSON.BinaryFrame.swift
+++ b/Sources/BSONABI/Views/BSON.BinaryFrame.swift
@@ -1,11 +1,9 @@
-import BSONTraversal
-
extension BSON
{
- /// Specifies the interpretation of a length header attached to a ``binary``
+ /// Specifies the interpretation of a length header attached to a ``BSON.AnyType/binary``
/// array.
@frozen public
- enum BinaryFrame:VariableLengthBSONFrame
+ enum BinaryFrame:FrameType
{
/// A binary array header starts its count after skipping the interceding
/// subtype byte.
diff --git a/Sources/BSONTypes/BSON.BinarySubtype.swift b/Sources/BSONABI/Views/BSON.BinarySubtype.swift
similarity index 100%
rename from Sources/BSONTypes/BSON.BinarySubtype.swift
rename to Sources/BSONABI/Views/BSON.BinarySubtype.swift
diff --git a/Sources/BSONTypes/BSON.BinarySubtypeError.swift b/Sources/BSONABI/Views/BSON.BinarySubtypeError.swift
similarity index 100%
rename from Sources/BSONTypes/BSON.BinarySubtypeError.swift
rename to Sources/BSONABI/Views/BSON.BinarySubtypeError.swift
diff --git a/Sources/BSONTypes/BSON.BinaryView.swift b/Sources/BSONABI/Views/BSON.BinaryView.swift
similarity index 93%
rename from Sources/BSONTypes/BSON.BinaryView.swift
rename to Sources/BSONABI/Views/BSON.BinaryView.swift
index 08a9ab8f..edcad569 100644
--- a/Sources/BSONTypes/BSON.BinaryView.swift
+++ b/Sources/BSONABI/Views/BSON.BinaryView.swift
@@ -1,5 +1,3 @@
-import BSONTraversal
-
extension BSON
{
/// A BSON binary array.
@@ -8,7 +6,7 @@ extension BSON
{
/// The contents of this binary array. This collection does *not*
/// include the leading subtype byte.
- public
+ public
let slice:Bytes
/// The subtype of this binary array.
public
@@ -36,11 +34,11 @@ extension BSON.BinaryView:Equatable
extension BSON.BinaryView:Sendable where Bytes:Sendable
{
}
-extension BSON.BinaryView:VariableLengthBSON where Bytes.SubSequence == Bytes
+extension BSON.BinaryView:BSON.FrameTraversable where Bytes.SubSequence == Bytes
{
public
typealias Frame = BSON.BinaryFrame
-
+
/// Removes the first element of the argument, attempts to cast it to a
/// ``BinarySubtype``, and stores the remainder in ``slice``.
///
@@ -79,7 +77,10 @@ extension BSON.BinaryView:VariableLengthBSON where Bytes.SubSequence == Bytes
}
}
}
-extension BSON.BinaryView:BSONView
+extension BSON.BinaryView:BSON.FrameView where Bytes.SubSequence == Bytes
+{
+}
+extension BSON.BinaryView
{
@inlinable public
init(_ value:BSON.AnyValue) throws
diff --git a/Sources/BSONTypes/BSON.BinaryViewError.Expectation.swift b/Sources/BSONABI/Views/BSON.BinaryViewError.Expectation.swift
similarity index 85%
rename from Sources/BSONTypes/BSON.BinaryViewError.Expectation.swift
rename to Sources/BSONABI/Views/BSON.BinaryViewError.Expectation.swift
index f45795d6..1895afe7 100644
--- a/Sources/BSONTypes/BSON.BinaryViewError.Expectation.swift
+++ b/Sources/BSONABI/Views/BSON.BinaryViewError.Expectation.swift
@@ -17,9 +17,9 @@ extension BSON.BinaryViewError.Expectation:CustomStringConvertible
switch self
{
case .subtype:
- return "subtype (1 byte)"
+ "subtype (1 byte)"
case .subheader:
- return "subheader (4 bytes)"
+ "subheader (4 bytes)"
}
}
}
diff --git a/Sources/BSONTypes/BSON.BinaryViewError.swift b/Sources/BSONABI/Views/BSON.BinaryViewError.swift
similarity index 100%
rename from Sources/BSONTypes/BSON.BinaryViewError.swift
rename to Sources/BSONABI/Views/BSON.BinaryViewError.swift
diff --git a/Sources/BSONTypes/BSON.DocumentFrame.swift b/Sources/BSONABI/Views/BSON.DocumentFrame.swift
similarity index 78%
rename from Sources/BSONTypes/BSON.DocumentFrame.swift
rename to Sources/BSONABI/Views/BSON.DocumentFrame.swift
index 5f0cad6c..5e1fc03a 100644
--- a/Sources/BSONTypes/BSON.DocumentFrame.swift
+++ b/Sources/BSONABI/Views/BSON.DocumentFrame.swift
@@ -1,11 +1,9 @@
-import BSONTraversal
-
extension BSON
{
- /// Specifies the interpretation of a length header attached to a ``document``,
- /// or a ``list`` document.
+ /// Specifies the interpretation of a length header attached to a ``BSON.AnyType/document``,
+ /// or a ``BSON.AnyType/list`` document.
@frozen public
- enum DocumentFrame:VariableLengthBSONFrame
+ enum DocumentFrame:FrameType
{
/// A document’s length header counts its own length. In other words,
/// it skips -4 bytes.
diff --git a/Sources/BSONStreaming/BSON.DocumentView (ext).swift b/Sources/BSONABI/Views/BSON.DocumentView.swift
similarity index 50%
rename from Sources/BSONStreaming/BSON.DocumentView (ext).swift
rename to Sources/BSONABI/Views/BSON.DocumentView.swift
index 5738815c..85f4dfb6 100644
--- a/Sources/BSONStreaming/BSON.DocumentView (ext).swift
+++ b/Sources/BSONABI/Views/BSON.DocumentView.swift
@@ -1,4 +1,77 @@
-import BSONTypes
+extension BSON
+{
+ /// A BSON document. The backing storage of this type is opaque,
+ /// permitting lazy parsing of its inline content.
+ @frozen public
+ struct DocumentView where Bytes:RandomAccessCollection
+ {
+ /// The raw data backing this document. This collection *does not*
+ /// include the trailing null byte that typically appears after its
+ /// inline field list.
+ public
+ let slice:Bytes
+
+ /// Stores the argument in ``slice`` unchanged.
+ ///
+ /// > Complexity: O(1)
+ @inlinable public
+ init(slice:Bytes)
+ {
+ self.slice = slice
+ }
+ }
+}
+extension BSON.DocumentView:Equatable
+{
+ /// Performs an exact byte-wise comparison on two lists.
+ /// Does not parse or validate the operands.
+ @inlinable public static
+ func == (lhs:Self, rhs:BSON.DocumentView>) -> Bool
+ {
+ lhs.slice.elementsEqual(rhs.slice)
+ }
+}
+extension BSON.DocumentView:Sendable where Bytes:Sendable
+{
+}
+extension BSON.DocumentView:BSON.FrameTraversable
+{
+ public
+ typealias Frame = BSON.DocumentFrame
+
+ /// Stores the argument in ``slice`` unchanged. Equivalent to ``init(slice:)``.
+ ///
+ /// > Complexity: O(1)
+ @inlinable public
+ init(slicing bytes:Bytes)
+ {
+ self.init(slice: bytes)
+ }
+}
+extension BSON.DocumentView:BSON.FrameView
+{
+ @inlinable public
+ init(_ value:BSON.AnyValue) throws
+ {
+ self = try value.cast(with: \.document)
+ }
+}
+extension BSON.DocumentView
+{
+ /// Indicates if this document contains no fields.
+ @inlinable public
+ var isEmpty:Bool { self.slice.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.slice.count }
+}
extension BSON.DocumentView<[UInt8]>
{
@@ -12,12 +85,13 @@ extension BSON.DocumentView<[UInt8]>
self.init(slice: document.bytes)
}
}
+
extension BSON.DocumentView
{
/// 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
+ /// 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.)
///
@@ -25,13 +99,13 @@ extension BSON.DocumentView
/// O(*n*), where *n* is the size of this document’s backing storage.
@inlinable public
func parse(
- to decode:(_ key:CodingKey, _ value:BSON.AnyValue) throws -> ()) throws
+ to decode:(CodingKey, BSON.AnyValue) throws -> ()) throws
where CodingKey:RawRepresentable
{
var input:BSON.Input = .init(self.slice)
while let code:UInt8 = input.next()
{
- let type:BSON = try .init(code: code)
+ 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)
@@ -63,7 +137,7 @@ extension BSON.DocumentView
return elements
}
}
-extension BSON.DocumentView:ExpressibleByDictionaryLiteral
+extension BSON.DocumentView:ExpressibleByDictionaryLiteral
where Bytes:RangeReplaceableCollection,
Bytes:RandomAccessCollection,
Bytes.Index == Int
@@ -72,14 +146,19 @@ extension BSON.DocumentView:ExpressibleByDictionaryLiteral
/// 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>)>)
+ 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))")
+
+ assert(output.destination.count == size, """
+ precomputed size (\(size)) does not match output size (\(output.destination.count))
+ """)
self.init(slice: output.destination)
}
@@ -89,8 +168,8 @@ extension BSON.DocumentView:ExpressibleByDictionaryLiteral
init(key:BSON.Key, value:BSON.AnyValue)
where Other:RandomAccessCollection
{
- self.init(
- fields: CollectionOfOne<(key:BSON.Key, value:BSON.AnyValue)>.init((key, value)))
+ self.init(fields:
+ CollectionOfOne<(key:BSON.Key, value:BSON.AnyValue)>.init((key, value)))
}
@inlinable public
diff --git a/Sources/BSONStreaming/BSON.ListView (ext).swift b/Sources/BSONABI/Views/BSON.ListView.swift
similarity index 56%
rename from Sources/BSONStreaming/BSON.ListView (ext).swift
rename to Sources/BSONABI/Views/BSON.ListView.swift
index d62f553e..f956517b 100644
--- a/Sources/BSONStreaming/BSON.ListView (ext).swift
+++ b/Sources/BSONABI/Views/BSON.ListView.swift
@@ -1,4 +1,78 @@
-import BSONTypes
+extension BSON
+{
+ /// A BSON list. The backing storage of this type is opaque,
+ /// permitting lazy parsing of its inline content.
+ @frozen public
+ struct ListView where Bytes:RandomAccessCollection
+ {
+ public
+ let document:BSON.DocumentView
+
+ @inlinable public
+ init(slice:Bytes)
+ {
+ self.document = .init(slice: slice)
+ }
+ }
+}
+extension BSON.ListView:Equatable
+{
+ /// Performs an exact byte-wise comparison on two lists.
+ /// Does not parse or validate the operands.
+ @inlinable public static
+ func == (lhs:Self, rhs:BSON.ListView>) -> Bool
+ {
+ lhs.document == rhs.document
+ }
+}
+extension BSON.ListView:Sendable where Bytes:Sendable
+{
+}
+extension BSON.ListView:BSON.FrameTraversable
+{
+ public
+ typealias Frame = BSON.DocumentFrame
+
+ /// Stores the argument in ``slice`` unchanged. Equivalent to ``init(slice:)``.
+ ///
+ /// > Complexity: O(1)
+ @inlinable public
+ init(slicing bytes:Bytes)
+ {
+ self.init(slice: bytes)
+ }
+}
+extension BSON.ListView:BSON.FrameView
+{
+ @inlinable public
+ init(_ value:BSON.AnyValue) throws
+ {
+ self = try value.cast(with: \.list)
+ }
+}
+extension BSON.ListView
+{
+ /// The raw data backing this list. This collection *does not*
+ /// include the trailing null byte that appears after its inline
+ /// elements list.
+ @inlinable public
+ var slice:Bytes { self.document.slice }
+
+ /// Indicates if this list contains no elements.
+ @inlinable public
+ var isEmpty:Bool { self.slice.isEmpty }
+
+ /// The length that would be encoded in this list’s prefixed header.
+ /// Equal to ``size``.
+ @inlinable public
+ var header:Int32 { .init(self.size) }
+
+ /// The size of this list 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.slice.count }
+}
extension BSON.ListView<[UInt8]>
{
@@ -12,10 +86,11 @@ extension BSON.ListView<[UInt8]>
self.init(slice: list.bytes)
}
}
+
extension BSON.ListView
{
/// Parses this list into key-value pairs in order, yielding each value to the
- /// provided closure. Parsing a list is slightly faster than parsing a general
+ /// provided closure. Parsing a list is slightly faster than parsing a general
/// ``DocumentView``, because this method ignores the document keys.
///
/// This method does *not* perform any key validation.
@@ -31,7 +106,7 @@ extension BSON.ListView
var input:BSON.Input = .init(self.slice)
while let code:UInt8 = input.next()
{
- let type:BSON = try .init(code: code)
+ let type:BSON.AnyType = try .init(code: code)
try input.parse(through: 0x00)
try decode(try input.parse(variant: type))
}
@@ -48,7 +123,7 @@ extension BSON.ListView
return elements
}
/// Splits this list’s inline key-value pairs into an array containing the
- /// values only. Parsing a list is slightly faster than parsing a general
+ /// values only. Parsing a list is slightly faster than parsing a general
/// ``DocumentView``, because this method ignores the document keys.
///
/// This method does *not* perform any key validation.
@@ -82,7 +157,7 @@ extension BSON.ListView:ExpressibleByArrayLiteral
self.init(slice: document.slice)
}
- @inlinable public
+ @inlinable public
init(arrayLiteral:BSON.AnyValue...)
{
self.init(elements: arrayLiteral)
diff --git a/Sources/BSONTypes/BSON.UTF8Frame.swift b/Sources/BSONABI/Views/BSON.UTF8Frame.swift
similarity index 86%
rename from Sources/BSONTypes/BSON.UTF8Frame.swift
rename to Sources/BSONABI/Views/BSON.UTF8Frame.swift
index 478d2b11..8166a4dd 100644
--- a/Sources/BSONTypes/BSON.UTF8Frame.swift
+++ b/Sources/BSONABI/Views/BSON.UTF8Frame.swift
@@ -1,10 +1,8 @@
-import BSONTraversal
-
extension BSON
{
/// Specifies the interpretation of a length header attached to UTF-8 ``string``.
@frozen public
- enum UTF8Frame:VariableLengthBSONFrame
+ enum UTF8Frame:FrameType
{
/// A UTF-8 string’s length header does not count its own length.
@inlinable public static
diff --git a/Sources/BSONTypes/BSON.UTF8View.swift b/Sources/BSONABI/Views/BSON.UTF8View.swift
similarity index 93%
rename from Sources/BSONTypes/BSON.UTF8View.swift
rename to Sources/BSONABI/Views/BSON.UTF8View.swift
index 0bd6f428..b83b8a7b 100644
--- a/Sources/BSONTypes/BSON.UTF8View.swift
+++ b/Sources/BSONABI/Views/BSON.UTF8View.swift
@@ -1,12 +1,10 @@
-import BSONTraversal
-
extension BSON
{
/// A BSON UTF-8 string. This string is allowed to contain null bytes.
///
/// This type can wrap potentially-invalid UTF-8 data, therefore it
/// is not backed by an instance of ``String``. Moreover, it (and not ``String``)
- /// is the payload of ``BSON.Value.string(_:)`` to ensure that long string
+ /// is the payload of ``BSON/AnyValue.string(_:)`` to ensure that long string
/// fields can be traversed in constant time.
///
/// To convert a UTF-8 string to a native Swift ``String`` (repairing invalid UTF-8),
@@ -17,7 +15,7 @@ extension BSON
/// The UTF-8 code units backing this string. This collection does *not*
/// include the trailing null byte that typically appears when this value
/// occurs inline in a document.
- public
+ public
let slice:Bytes
@inlinable public
@@ -45,7 +43,7 @@ extension BSON.UTF8View where Bytes:RangeReplaceableCollection
}
}
extension BSON.UTF8View:ExpressibleByStringLiteral,
- ExpressibleByExtendedGraphemeClusterLiteral,
+ ExpressibleByExtendedGraphemeClusterLiteral,
ExpressibleByUnicodeScalarLiteral
{
@inlinable public
@@ -119,7 +117,7 @@ extension BSON.UTF8View:CustomStringConvertible
.init(bson: self)
}
}
-extension BSON.UTF8View:VariableLengthBSON where Bytes:RandomAccessCollection
+extension BSON.UTF8View:BSON.FrameTraversable where Bytes:RandomAccessCollection
{
public
typealias Frame = BSON.UTF8Frame
@@ -133,7 +131,7 @@ extension BSON.UTF8View:VariableLengthBSON where Bytes:RandomAccessCollection
+extension BSON.UTF8View:BSON.FrameView where Bytes:RandomAccessCollection
{
@inlinable public
init(_ value:BSON.AnyValue) throws
diff --git a/Sources/BSONDecoding/Containers/BSON.ExplicitField.swift b/Sources/BSONDecoding/BSON.FieldDecoder.swift
similarity index 73%
rename from Sources/BSONDecoding/Containers/BSON.ExplicitField.swift
rename to Sources/BSONDecoding/BSON.FieldDecoder.swift
index f949b0a8..18d7c6fa 100644
--- a/Sources/BSONDecoding/Containers/BSON.ExplicitField.swift
+++ b/Sources/BSONDecoding/BSON.FieldDecoder.swift
@@ -1,7 +1,13 @@
extension BSON
+{
+ @available(*, deprecated, renamed: "FieldDecoder")
+ public
+ typealias ExplicitField = FieldDecoder
+}
+extension BSON
{
@frozen public
- struct ExplicitField where Bytes:RandomAccessCollection, Key:Sendable
+ struct FieldDecoder where Bytes:RandomAccessCollection, Key:Sendable
{
public
let key:Key
@@ -16,7 +22,7 @@ extension BSON
}
}
}
-extension BSON.ExplicitField:BSONScope
+extension BSON.FieldDecoder:BSON.TraceableDecoder
{
/// Decodes the value of this field with the given decoder.
/// Throws a ``BSON/DecodingError`` wrapping the underlying
diff --git a/Sources/BSONDecoding/Containers/BSON.ImplicitField.swift b/Sources/BSONDecoding/BSON.OptionalDecoder.swift
similarity index 81%
rename from Sources/BSONDecoding/Containers/BSON.ImplicitField.swift
rename to Sources/BSONDecoding/BSON.OptionalDecoder.swift
index 5196dc81..499aa7f0 100644
--- a/Sources/BSONDecoding/Containers/BSON.ImplicitField.swift
+++ b/Sources/BSONDecoding/BSON.OptionalDecoder.swift
@@ -1,11 +1,17 @@
extension BSON
+{
+ @available(*, deprecated, renamed: "OptionalDecoder")
+ public
+ typealias ImplicitField = OptionalDecoder
+}
+extension BSON
{
/// A field that may or may not exist in a document. This type is
/// the return value of ``Dictionary``’s non-optional subscript, and
/// is useful for obtaining structured diagnostics for “key-not-found”
/// scenarios.
@frozen public
- struct ImplicitField where Bytes:RandomAccessCollection, Key:Sendable
+ struct OptionalDecoder where Bytes:RandomAccessCollection, Key:Sendable
{
public
let key:Key
@@ -20,25 +26,25 @@ extension BSON
}
}
}
-extension BSON.ImplicitField
+extension BSON.OptionalDecoder
{
@inlinable public static
func ?? (lhs:Self, rhs:@autoclosure () -> Self) -> Self
{
if case nil = lhs.value
{
- return rhs()
+ rhs()
}
else
{
- return lhs
+ lhs
}
}
}
-extension BSON.ImplicitField
+extension BSON.OptionalDecoder
{
/// Gets the value of this key, throwing a ``BSON.DocumentKeyError``
- /// if it is [`nil`](). This is a distinct condition from an explicit
+ /// if it is nil. This is a distinct condition from an explicit
/// ``BSON.null`` value, which will be returned without throwing an error.
@inlinable public
func decode() throws -> BSON.AnyValue
@@ -53,7 +59,7 @@ extension BSON.ImplicitField
}
}
}
-extension BSON.ImplicitField:BSONScope
+extension BSON.OptionalDecoder:BSON.TraceableDecoder
{
/// Decodes the value of this implicit field with the given decoder, throwing a
/// ``BSON.DocumentKeyError`` if it does not exist. Throws a
diff --git a/Sources/BSONDecoding/Decoding/BSONScope.swift b/Sources/BSONDecoding/BSON.TraceableDecoder.swift
similarity index 85%
rename from Sources/BSONDecoding/Decoding/BSONScope.swift
rename to Sources/BSONDecoding/BSON.TraceableDecoder.swift
index 79717e7b..6756eece 100644
--- a/Sources/BSONDecoding/Decoding/BSONScope.swift
+++ b/Sources/BSONDecoding/BSON.TraceableDecoder.swift
@@ -1,6 +1,13 @@
-/// A type that represents a scope for decoding operations.
+extension BSON
+{
+ /// A type that represents a scope for decoding operations.
+ public
+ typealias TraceableDecoder = _BSONTraceableDecoder
+}
+
+/// The name of this protocol is ``BSON.TraceableDecoder``.
public
-protocol BSONScope
+protocol _BSONTraceableDecoder
{
associatedtype Bytes:RandomAccessCollection
@@ -9,7 +16,8 @@ protocol BSONScope
/// should annotate the error with appropriate context and re-throw it.
func decode(with decode:(BSON.AnyValue) throws -> T) throws -> T
}
-extension BSONScope
+
+extension BSON.TraceableDecoder
{
@inlinable public
func decode(using _:CodingKey.Type = CodingKey.self,
@@ -31,7 +39,7 @@ extension BSONScope
// We should probably replace this with a dedicated API for binary subschema.
@inlinable public
func decode(as _:View.Type,
- with decode:(View) throws -> T) throws -> T where View:BSONView
+ with decode:(View) throws -> T) throws -> T where View:BSON.FrameView
{
try self.decode { try decode(try .init($0)) }
}
diff --git a/Sources/BSONDecoding/Containers/BSON.DocumentView (ext).swift b/Sources/BSONDecoding/Containers/BSON.DocumentView (ext).swift
index 62e6bb2e..6d4321de 100644
--- a/Sources/BSONDecoding/Containers/BSON.DocumentView (ext).swift
+++ b/Sources/BSONDecoding/Containers/BSON.DocumentView (ext).swift
@@ -1,11 +1,10 @@
extension BSON.DocumentView
{
- /// @import(BSONView)
/// Decorates the ``BSON.AnyValue``-yielding overload of this method with one that
/// yields the key-value pairs as fields.
@inlinable public
func parse(
- to decode:(_ field:BSON.ExplicitField) throws -> ()) throws
+ to decode:(_ field:BSON.FieldDecoder) throws -> ()) throws
{
try self.parse
{
diff --git a/Sources/BSONDecoding/Containers/BSON.ListView (ext).swift b/Sources/BSONDecoding/Containers/BSON.ListView (ext).swift
index 466d7def..11c0f0bf 100644
--- a/Sources/BSONDecoding/Containers/BSON.ListView (ext).swift
+++ b/Sources/BSONDecoding/Containers/BSON.ListView (ext).swift
@@ -1,11 +1,10 @@
extension BSON.ListView
{
- /// @import(BSONView)
/// Decorates the ``BSON.AnyValue``-yielding overload of this method with one that
/// enumerates the elements and yields them as fields.
@inlinable public
func parse(
- to decode:(_ field:BSON.ExplicitField) throws -> ()) throws
+ to decode:(_ field:BSON.FieldDecoder) throws -> ()) throws
{
var index:Int = 0
try self.parse
diff --git a/Sources/BSONDecoding/Decodability/BSONBinaryViewDecodable.swift b/Sources/BSONDecoding/Decodability/BSONBinaryViewDecodable.swift
index 68c5899e..aec582ce 100644
--- a/Sources/BSONDecoding/Decodability/BSONBinaryViewDecodable.swift
+++ b/Sources/BSONDecoding/Decodability/BSONBinaryViewDecodable.swift
@@ -9,7 +9,7 @@ protocol BSONBinaryViewDecodable:BSONDecodable
extension BSONBinaryViewDecodable
{
/// Attempts to cast the given variant value to a binary array, and then
- /// delegates to this type’s ``init(bson:)`` witness.
+ /// delegates to this type’s ``init(bson:) [56R02]`` witness.
@inlinable public
init(bson:BSON.AnyValue>) throws
{
diff --git a/Sources/BSONDecoding/Decodability/BSONDecodable.swift b/Sources/BSONDecoding/Decodability/BSONDecodable.swift
index e15a9382..239f9c67 100644
--- a/Sources/BSONDecoding/Decodability/BSONDecodable.swift
+++ b/Sources/BSONDecoding/Decodability/BSONDecodable.swift
@@ -1,9 +1,10 @@
+import BSONABI
/// A type that can be decoded from a BSON variant value backed by
/// some type of storage not particular to the decoded type.
///
-/// This protocol is parallel and unrelated to ``BSONDecodableView`` to
+/// This protocol is parallel and unrelated to ``BSON.FrameView`` to
/// emphasize the performance characteristics of types that conform to
-/// this protocol and not ``BSONDecodableView``.
+/// this protocol and not ``BSON.FrameView``.
public
protocol BSONDecodable
{
diff --git a/Sources/BSONDecoding/Decodability/BSONStringDecodable.swift b/Sources/BSONDecoding/Decodability/BSONStringDecodable.swift
index 96cdf67a..e0e3a145 100644
--- a/Sources/BSONDecoding/Decodability/BSONStringDecodable.swift
+++ b/Sources/BSONDecoding/Decodability/BSONStringDecodable.swift
@@ -14,7 +14,7 @@ protocol BSONStringDecodable:BSONDecodable
extension BSONStringDecodable
{
/// Attempts to cast the given variant value to a string, and then
- /// delegates to this type’s ``init(bson:)`` witness.
+ /// delegates to this type’s ``init(bson:) [6DO67]`` witness.
@inlinable public
init(bson:BSON.AnyValue>) throws
{
diff --git a/Sources/BSONDecoding/Decoding/BSON.DecodingError.swift b/Sources/BSONDecoding/Decoding/BSON.DecodingError.swift
index 49b39cc9..90101b99 100644
--- a/Sources/BSONDecoding/Decoding/BSON.DecodingError.swift
+++ b/Sources/BSONDecoding/Decoding/BSON.DecodingError.swift
@@ -24,8 +24,8 @@ extension BSON
extension BSON.DecodingError:Equatable where Location:Equatable
{
/// Compares the ``location`` properties and the ``underlying``
- /// errors of the operands for equality, returning [`true`]()
- /// if they are equal. Always returns [`false`]() if (any of)
+ /// errors of the operands for equality, returning `true`
+ /// if they are equal. Always returns `false` if (any of)
/// the underlying ``Error`` existentials are not ``Equatable``.
public static
func == (lhs:Self, rhs:Self) -> Bool
diff --git a/Sources/BSONDecoding/Decoding/BSON.DocumentDecoder.Iterator.swift b/Sources/BSONDecoding/Decoding/BSON.DocumentDecoder.Iterator.swift
index a0f1c660..6e7832e5 100644
--- a/Sources/BSONDecoding/Decoding/BSON.DocumentDecoder.Iterator.swift
+++ b/Sources/BSONDecoding/Decoding/BSON.DocumentDecoder.Iterator.swift
@@ -16,7 +16,7 @@ extension BSON.DocumentDecoder
extension BSON.DocumentDecoder.Iterator:IteratorProtocol
{
@inlinable public mutating
- func next() -> BSON.ExplicitField?
+ func next() -> BSON.FieldDecoder?
{
self.base.next().map { .init(key: $0.key, value: $0.value) }
}
diff --git a/Sources/BSONDecoding/Decoding/BSON.DocumentDecoder.swift b/Sources/BSONDecoding/Decoding/BSON.DocumentDecoder.swift
index f71cca17..bbc43317 100644
--- a/Sources/BSONDecoding/Decoding/BSON.DocumentDecoder.swift
+++ b/Sources/BSONDecoding/Decoding/BSON.DocumentDecoder.swift
@@ -19,13 +19,13 @@ extension BSON
}
}
}
-extension BSON.DocumentDecoder:BSONDecoder
+extension BSON.DocumentDecoder:BSON.Decoder
{
/// Attempts to load a document decoder from the given variant.
///
/// - Returns:
/// A document decoder derived from the payload of this variant if it matches
- /// ``case document(_:)`` or ``case list(_:)``, [`nil`]() otherwise.
+ /// ``document(_:)`` **or** ``list(_:)``, nil otherwise.
@inlinable public
init(parsing bson:__shared BSON.AnyValue) throws
{
@@ -53,7 +53,7 @@ extension BSON.DocumentDecoder
/// comparison would drop one of the values.
///
/// To get a plain array of key-value pairs with no decoding interface, call the
- /// document view’s ``BSON.DocumentView parse()`` method instead.
+ /// document view’s ``BSON.DocumentView/parse()`` method instead.
///
/// > Complexity:
/// O(*n*), where *n* is the number of fields in the source document.
@@ -94,10 +94,10 @@ extension BSON.DocumentDecoder:Sequence
extension BSON.DocumentDecoder
{
@inlinable public __consuming
- func single() throws -> BSON.ExplicitField
+ func single() throws -> BSON.FieldDecoder
{
- var single:BSON.ExplicitField? = nil
- for field:BSON.ExplicitField in self
+ var single:BSON.FieldDecoder? = nil
+ for field:BSON.FieldDecoder in self
{
if case nil = single
{
@@ -117,13 +117,13 @@ extension BSON.DocumentDecoder
}
@inlinable public
- subscript(key:CodingKey) -> BSON.ExplicitField?
+ subscript(key:CodingKey) -> BSON.OptionalDecoder
{
- self.index[key].map { .init(key: key, value: $0) }
+ .init(key: key, value: self.index[key])
}
@inlinable public
- subscript(key:CodingKey) -> BSON.ImplicitField
+ subscript(key:CodingKey) -> BSON.FieldDecoder?
{
- .init(key: key, value: self.index[key])
+ self.index[key].map { .init(key: key, value: $0) }
}
}
diff --git a/Sources/BSONDecoding/Decoding/BSON.DocumentKeyError.swift b/Sources/BSONDecoding/Decoding/BSON.DocumentKeyError.swift
index 777974e9..8c230556 100644
--- a/Sources/BSONDecoding/Decoding/BSON.DocumentKeyError.swift
+++ b/Sources/BSONDecoding/Decoding/BSON.DocumentKeyError.swift
@@ -32,9 +32,9 @@ extension BSON.DocumentKeyError:NamedError
switch self
{
case .duplicate(let key):
- return "duplicate key '\(key)'"
+ "duplicate key '\(key)'"
case .undefined(let key):
- return "undefined key '\(key)'"
+ "undefined key '\(key)'"
}
}
}
diff --git a/Sources/BSONDecoding/Decoding/BSON.ListDecoder.swift b/Sources/BSONDecoding/Decoding/BSON.ListDecoder.swift
index 85ae7583..103f441e 100644
--- a/Sources/BSONDecoding/Decoding/BSON.ListDecoder.swift
+++ b/Sources/BSONDecoding/Decoding/BSON.ListDecoder.swift
@@ -15,7 +15,7 @@ extension BSON
}
}
}
-extension BSON.ListDecoder:BSONDecoder
+extension BSON.ListDecoder:BSON.Decoder
{
/// Attempts to unwrap and parse an array-decoder from the given variant.
///
@@ -24,7 +24,7 @@ extension BSON.ListDecoder:BSONDecoder
///
/// - Returns:
/// The payload of the variant, parsed to a list decoder, if it matches
- /// ``case list(_:)`` and could be successfully parsed, [`nil`]() otherwise.
+ /// ``case list(_:)`` and could be successfully parsed, nil otherwise.
///
/// > Complexity:
// O(*n*), where *n* is the number of elements in the source list.
@@ -70,7 +70,7 @@ extension BSON.ListDecoder:RandomAccessCollection
self.elements.endIndex
}
@inlinable public
- subscript(index:Int) -> BSON.ExplicitField
+ subscript(index:Int) -> BSON.FieldDecoder
{
.init(key: index, value: self.elements[index])
}
diff --git a/Sources/BSONDecoding/Decoding/BSON.ShapeError.swift b/Sources/BSONDecoding/Decoding/BSON.ShapeError.swift
index 9b04c355..025c15fd 100644
--- a/Sources/BSONDecoding/Decoding/BSON.ShapeError.swift
+++ b/Sources/BSONDecoding/Decoding/BSON.ShapeError.swift
@@ -26,13 +26,13 @@ extension BSON.ShapeError:CustomStringConvertible
switch self.expected
{
case nil:
- return "Invalid length (\(self.length))."
+ "Invalid length (\(self.length))."
case .length(let length)?:
- return "Invalid length (\(self.length)), expected \(length) elements."
+ "Invalid length (\(self.length)), expected \(length) elements."
case .multiple(of: let stride)?:
- return "Invalid length (\(self.length)), expected multiple of \(stride)."
+ "Invalid length (\(self.length)), expected multiple of \(stride)."
}
}
}
diff --git a/Sources/BSONDecoding/Decoding/BSON.SingleKeyError.swift b/Sources/BSONDecoding/Decoding/BSON.SingleKeyError.swift
index 0b589b15..454ac834 100644
--- a/Sources/BSONDecoding/Decoding/BSON.SingleKeyError.swift
+++ b/Sources/BSONDecoding/Decoding/BSON.SingleKeyError.swift
@@ -26,9 +26,9 @@ extension BSON.SingleKeyError:NamedError
switch self
{
case .none:
- return "no keys in single-field document"
+ "no keys in single-field document"
case .multiple:
- return "multiple keys in single-field document"
+ "multiple keys in single-field document"
}
}
}
diff --git a/Sources/BSONDecoding/Dictionary (ext).swift b/Sources/BSONDecoding/Dictionary (ext).swift
index cf1dbaf4..369e3340 100644
--- a/Sources/BSONDecoding/Dictionary (ext).swift
+++ b/Sources/BSONDecoding/Dictionary (ext).swift
@@ -10,7 +10,7 @@ extension Dictionary:BSONDocumentViewDecodable, BSONDecodable
self.init()
try bson.parse
{
- (field:BSON.ExplicitField) in
+ (field:BSON.FieldDecoder) in
if case _? = self.updateValue(try field.decode(to: Value.self),
forKey: field.key.rawValue)
diff --git a/Sources/BSONDecoding/Extensions/Double (ext).swift b/Sources/BSONDecoding/Extensions/Double (ext).swift
index 0b69cef5..d5dfb02c 100644
--- a/Sources/BSONDecoding/Extensions/Double (ext).swift
+++ b/Sources/BSONDecoding/Extensions/Double (ext).swift
@@ -1,3 +1,3 @@
extension Double:BSONDecodable
{
-}
\ No newline at end of file
+}
diff --git a/Sources/BSONDecoding/Legacy/BSON.KeyedDecoder.swift b/Sources/BSONDecoding/Legacy/BSON.KeyedDecoder.swift
index 481cc1d8..e65ef100 100644
--- a/Sources/BSONDecoding/Legacy/BSON.KeyedDecoder.swift
+++ b/Sources/BSONDecoding/Legacy/BSON.KeyedDecoder.swift
@@ -66,7 +66,7 @@ extension BSON.KeyedDecoder:KeyedDecodingContainerProtocol
public
func decode(_:T.Type, forKey key:Key) throws -> T where T:Decodable
{
- return try .init(from: try self.singleValueContainer(forKey: key))
+ try .init(from: try self.singleValueContainer(forKey: key))
}
func decodeNil(forKey key:Key) throws -> Bool
{
diff --git a/Sources/BSONDecoding/README.md b/Sources/BSONDecoding/README.md
new file mode 100644
index 00000000..cd4aae9f
--- /dev/null
+++ b/Sources/BSONDecoding/README.md
@@ -0,0 +1 @@
+# ``/BSONDecoding``
diff --git a/Sources/BSONDecoding/exports.swift b/Sources/BSONDecoding/exports.swift
index 16493bb2..39f8f8b5 100644
--- a/Sources/BSONDecoding/exports.swift
+++ b/Sources/BSONDecoding/exports.swift
@@ -1 +1 @@
-@_exported import BSON
+@_exported import enum BSONABI.BSON
diff --git a/Sources/BSONDecodingTests/Main.DecodeBinary.swift b/Sources/BSONDecodingTests/Main.DecodeBinary.swift
new file mode 100644
index 00000000..1b25951e
--- /dev/null
+++ b/Sources/BSONDecodingTests/Main.DecodeBinary.swift
@@ -0,0 +1,37 @@
+import BSONDecoding
+import Testing
+
+extension Main
+{
+ enum DecodeBinary
+ {
+ }
+}
+extension Main.DecodeBinary:TestBattery
+{
+ static
+ func run(tests:TestGroup)
+ {
+ if let tests:TestGroup = tests / "md5"
+ {
+ let md5:BSON.BinaryView> = .init(subtype: .md5,
+ slice: [0xff, 0xfe, 0xfd])
+ let bson:BSON.DocumentView> =
+ [
+ "md5": .binary(md5),
+ ]
+
+ tests.do
+ {
+ let bson:BSON.DocumentDecoder> = try .init(
+ parsing: bson)
+ let decoded:BSON.BinaryView> = try bson["md5"].decode(
+ as: BSON.BinaryView>.self)
+ {
+ $0
+ }
+ tests.expect(true: md5 == decoded)
+ }
+ }
+ }
+}
diff --git a/Sources/BSONDecodingTests/Main.DecodeDocument.swift b/Sources/BSONDecodingTests/Main.DecodeDocument.swift
new file mode 100644
index 00000000..200c66a8
--- /dev/null
+++ b/Sources/BSONDecodingTests/Main.DecodeDocument.swift
@@ -0,0 +1,100 @@
+import BSONDecoding
+import Testing
+
+extension Main
+{
+ enum DecodeDocument
+ {
+ }
+}
+extension Main.DecodeDocument:TestBattery
+{
+ static
+ func run(tests:TestGroup)
+ {
+
+ let degenerate:BSON.DocumentView<[UInt8]> =
+ [
+ "present": .null,
+ "present": true,
+ ]
+ let bson:BSON.DocumentView<[UInt8]> =
+ [
+ "present": .null,
+ "inhabited": true,
+ ]
+
+ Self.run(tests / "key-not-unique", bson: degenerate,
+ catching: BSON.DocumentKeyError.duplicate("present"))
+ {
+ try $0["not-present"].decode(to: Bool.self)
+ }
+
+ Self.run(tests / "key-not-present", bson: bson,
+ catching: BSON.DocumentKeyError.undefined("not-present"))
+ {
+ try $0["not-present"].decode(to: Bool.self)
+ }
+
+ Self.run(tests / "key-matching", bson: bson,
+ to: true)
+ {
+ try $0["inhabited"].decode(to: Bool.self)
+ }
+
+ Self.run(tests / "key-not-matching", bson: bson,
+ catching: BSON.DecodingError.init(
+ BSON.TypecastError>>.init(invalid: .bool),
+ in: "inhabited"))
+ {
+ try $0["inhabited"].decode(to: String.self)
+ }
+
+ Self.run(tests / "key-not-matching-inhabited", bson: bson,
+ catching: BSON.DecodingError.init(
+ BSON.TypecastError.init(invalid: .null),
+ in: "present"))
+ {
+ try $0["present"].decode(to: Bool.self)
+ }
+
+ Self.run(tests / "key-inhabited", bson: bson,
+ to: .some(true))
+ {
+ try $0["inhabited"].decode(to: Bool?.self)
+ }
+
+ Self.run(tests / "key-null", bson: bson,
+ to: nil)
+ {
+ try $0["present"].decode(to: Bool?.self)
+ }
+
+ Self.run(tests / "key-optional", bson: bson,
+ to: nil)
+ {
+ try $0["not-present"]?.decode(to: Bool.self)
+ }
+
+ Self.run(tests / "key-optional-null", bson: bson,
+ to: .some(.none))
+ {
+ try $0["present"]?.decode(to: Bool?.self)
+ }
+
+ Self.run(tests / "key-optional-inhabited", bson: bson,
+ to: .some(.some(true)))
+ {
+ try $0["inhabited"]?.decode(to: Bool?.self)
+ }
+
+ // should throw an error instead of returning nil.
+ Self.run(tests / "key-optional-not-inhabited", bson: bson,
+ catching: BSON.DecodingError.init(
+ BSON.TypecastError.init(invalid: .null),
+ in: "present"))
+ {
+ try $0["present"]?.decode(to: Bool.self)
+ }
+ }
+}
diff --git a/Sources/BSONDecodingTests/Main.DecodeList.swift b/Sources/BSONDecodingTests/Main.DecodeList.swift
new file mode 100644
index 00000000..425e1939
--- /dev/null
+++ b/Sources/BSONDecodingTests/Main.DecodeList.swift
@@ -0,0 +1,119 @@
+import BSONDecoding
+import Testing
+
+extension Main
+{
+ enum DecodeList
+ {
+ }
+}
+extension Main.DecodeList:TestBattery
+{
+ static
+ func run(tests:TestGroup)
+ {
+ let bson:BSON.DocumentView<[UInt8]> =
+ [
+ "none": [],
+ "two": ["a", "b"],
+ "three": ["a", "b", "c"],
+ "four": ["a", "b", "c", "d"],
+
+ "heterogenous": ["a", "b", 0, "d"],
+ ]
+
+ Self.run(tests / "none-to-two", bson: bson,
+ catching: BSON.DecodingError.init(
+ BSON.ShapeError.init(invalid: 0, expected: .length(2)),
+ in: "none"))
+ {
+ try $0["none"].decode
+ {
+ try $0.shape.expect(length: 2)
+ }
+ }
+
+ Self.run(tests / "two-to-two", bson: bson,
+ to: ["a", "b"])
+ {
+ try $0["two"].decode
+ {
+ try $0.shape.expect(length: 2)
+ return try $0.map { try $0.decode(to: String.self) }
+ }
+ }
+
+ Self.run(tests / "three-to-two", bson: bson,
+ catching: BSON.DecodingError.init(
+ BSON.ShapeError.init(invalid: 3, expected: .length(2)),
+ in: "three"))
+ {
+ try $0["three"].decode
+ {
+ try $0.shape.expect(length: 2)
+ }
+ }
+
+ Self.run(tests / "three-by-two", bson: bson,
+ catching: BSON.DecodingError.init(
+ BSON.ShapeError.init(invalid: 3, expected: .multiple(of: 2)),
+ in: "three"))
+ {
+ try $0["three"].decode
+ {
+ try $0.shape.expect(multipleOf: 2)
+ }
+ }
+
+ Self.run(tests / "four-by-two", bson: bson,
+ to: ["a", "b", "c", "d"])
+ {
+ try $0["four"].decode
+ {
+ try $0.shape.expect(multipleOf: 2)
+ return try $0.map { try $0.decode(to: String.self) }
+ }
+ }
+
+ Self.run(tests / "map", bson: bson,
+ to: ["a", "b", "c", "d"])
+ {
+ try $0["four"].decode(to: [String].self)
+ }
+
+ Self.run(tests / "map-invalid", bson: bson,
+ catching: BSON.DecodingError.init(
+ BSON.DecodingError.init(
+ BSON.TypecastError>>.init(
+ invalid: .int32),
+ in: 2),
+ in: "heterogenous"))
+ {
+ try $0["heterogenous"].decode(to: [String].self)
+ }
+
+ Self.run(tests / "element", bson: bson, to: "c")
+ {
+ try $0["four"].decode
+ {
+ try $0.shape.expect { 2 < $0 }
+ return try $0[2].decode(to: String.self)
+ }
+ }
+
+ Self.run(tests / "element-invalid", bson: bson,
+ catching: BSON.DecodingError.init(
+ BSON.DecodingError.init(
+ BSON.TypecastError>>.init(
+ invalid: .int32),
+ in: 2),
+ in: "heterogenous"))
+ {
+ try $0["heterogenous"].decode
+ {
+ try $0.shape.expect { 2 < $0 }
+ return try $0[2].decode(to: String.self)
+ }
+ }
+ }
+}
diff --git a/Sources/BSONDecodingTests/Main.DecodeNumeric.swift b/Sources/BSONDecodingTests/Main.DecodeNumeric.swift
new file mode 100644
index 00000000..7285cd6c
--- /dev/null
+++ b/Sources/BSONDecodingTests/Main.DecodeNumeric.swift
@@ -0,0 +1,53 @@
+import BSONDecoding
+import Testing
+
+extension Main
+{
+ enum DecodeNumeric
+ {
+ }
+}
+extension Main.DecodeNumeric:TestBattery
+{
+ static
+ func run(tests:TestGroup)
+ {
+ let bson:BSON.DocumentView<[UInt8]> =
+ [
+ "int32": .int32(0x7fff_ffff),
+ "int64": .int64(0x7fff_ffff_ffff_ffff),
+ "uint64": .uint64(0x7fff_ffff_ffff_ffff),
+ ]
+
+ Self.run(tests / "int32-to-uint8", bson: bson,
+ catching: BSON.DecodingError.init(
+ BSON.IntegerOverflowError.int32(0x7fff_ffff),
+ in: "int32"))
+ {
+ try $0["int32"].decode(to: UInt8.self)
+ }
+
+ Self.run(tests / "int32-to-int32", bson: bson,
+ to: 0x7fff_ffff)
+ {
+ try $0["int32"].decode(to: Int32.self)
+ }
+
+ Self.run(tests / "int32-to-int", bson: bson,
+ to: 0x7fff_ffff)
+ {
+ try $0["int32"].decode(to: Int.self)
+ }
+
+ Self.run(tests / "int64-to-int", bson: bson,
+ to: 0x7fff_ffff_ffff_ffff)
+ {
+ try $0["int64"].decode(to: Int.self)
+ }
+ Self.run(tests / "uint64-to-int", bson: bson,
+ to: 0x7fff_ffff_ffff_ffff)
+ {
+ try $0["uint64"].decode(to: Int.self)
+ }
+ }
+}
diff --git a/Sources/BSONDecodingTests/Main.DecodeString.swift b/Sources/BSONDecodingTests/Main.DecodeString.swift
new file mode 100644
index 00000000..1f7bbe27
--- /dev/null
+++ b/Sources/BSONDecodingTests/Main.DecodeString.swift
@@ -0,0 +1,61 @@
+import BSONDecoding
+import Testing
+
+extension Main
+{
+ enum DecodeString
+ {
+ }
+}
+extension Main.DecodeString:TestBattery
+{
+ static
+ func run(tests:TestGroup)
+ {
+ let bson:BSON.DocumentView<[UInt8]> =
+ [
+ "string": "e\u{0301}e\u{0301}",
+ "character": "e\u{0301}",
+ "unicode-scalar": "e",
+ ]
+
+ Self.run(tests / "unicode-scalar-from-string", bson: bson,
+ catching: BSON.DecodingError.init(
+ BSON.ValueError.init(invalid: "e\u{0301}e\u{0301}"),
+ in: "string"))
+ {
+ try $0["string"].decode(to: Unicode.Scalar.self)
+ }
+ Self.run(tests / "unicode-scalar-from-character", bson: bson,
+ catching: BSON.DecodingError.init(
+ BSON.ValueError.init(invalid: "e\u{0301}"),
+ in: "character"))
+ {
+ try $0["character"].decode(to: Unicode.Scalar.self)
+ }
+ Self.run(tests / "unicode-scalar", bson: bson,
+ to: "e")
+ {
+ try $0["unicode-scalar"].decode(to: Unicode.Scalar.self)
+ }
+
+ Self.run(tests / "character-from-string", bson: bson,
+ catching: BSON.DecodingError.init(
+ BSON.ValueError.init(invalid: "e\u{0301}e\u{0301}"),
+ in: "string"))
+ {
+ try $0["string"].decode(to: Character.self)
+ }
+ Self.run(tests / "character", bson: bson,
+ to: "e\u{0301}")
+ {
+ try $0["character"].decode(to: Character.self)
+ }
+
+ Self.run(tests / "string", bson: bson,
+ to: "e\u{0301}e\u{0301}")
+ {
+ try $0["string"].decode(to: String.self)
+ }
+ }
+}
diff --git a/Sources/BSONDecodingTests/Main.DecodeVoid.swift b/Sources/BSONDecodingTests/Main.DecodeVoid.swift
new file mode 100644
index 00000000..92cb547d
--- /dev/null
+++ b/Sources/BSONDecodingTests/Main.DecodeVoid.swift
@@ -0,0 +1,37 @@
+import BSONDecoding
+import Testing
+
+extension Main
+{
+ enum DecodeVoid
+ {
+ }
+}
+extension Main.DecodeVoid:TestBattery
+{
+ static
+ func run(tests:TestGroup)
+ {
+ let bson:BSON.DocumentView<[UInt8]> =
+ [
+ "null": .null,
+ "max": .max,
+ "min": .min,
+ ]
+
+ (tests / "null")?.do
+ {
+ let bson:BSON.DocumentDecoder = try .init(
+ parsing: bson)
+ let _:Never? = try bson["null"].decode(to: Never?.self)
+ }
+ Self.run(tests / "max", bson: bson, to: .init())
+ {
+ try $0["max"].decode(to: BSON.Max.self)
+ }
+ Self.run(tests / "min", bson: bson, to: .init())
+ {
+ try $0["min"].decode(to: BSON.Min.self)
+ }
+ }
+}
diff --git a/Sources/BSONDecodingTests/Main.swift b/Sources/BSONDecodingTests/Main.swift
index 8e02ec7c..3aa40f96 100644
--- a/Sources/BSONDecodingTests/Main.swift
+++ b/Sources/BSONDecodingTests/Main.swift
@@ -1,345 +1,16 @@
-import BSONDecoding
import Testing
@main
-enum Main:SyncTests
+enum Main:TestMain
{
static
- func run(tests:Tests)
- {
- do
- {
- let bson:BSON.DocumentView<[UInt8]> =
- [
- "null": .null,
- "max": .max,
- "min": .min,
- ]
-
- (tests / "null")?.do
- {
- let bson:BSON.DocumentDecoder = try .init(
- parsing: bson)
- let _:Never? = try bson["null"].decode(to: Never?.self)
- }
- TestDecoding(tests / "max", bson: bson, to: .init())
- {
- try $0["max"].decode(to: BSON.Max.self)
- }
- TestDecoding(tests / "min", bson: bson, to: .init())
- {
- try $0["min"].decode(to: BSON.Min.self)
- }
- }
- if let tests:TestGroup = tests / "numeric"
- {
-
- let bson:BSON.DocumentView<[UInt8]> =
- [
- "int32": .int32(0x7fff_ffff),
- "int64": .int64(0x7fff_ffff_ffff_ffff),
- "uint64": .uint64(0x7fff_ffff_ffff_ffff),
- ]
-
- TestDecoding(tests / "int32-to-uint8", bson: bson,
- catching: BSON.DecodingError.init(
- BSON.IntegerOverflowError.int32(0x7fff_ffff),
- in: "int32"))
- {
- try $0["int32"].decode(to: UInt8.self)
- }
-
- TestDecoding(tests / "int32-to-int32", bson: bson,
- to: 0x7fff_ffff)
- {
- try $0["int32"].decode(to: Int32.self)
- }
-
- TestDecoding(tests / "int32-to-int", bson: bson,
- to: 0x7fff_ffff)
- {
- try $0["int32"].decode(to: Int.self)
- }
-
- TestDecoding(tests / "int64-to-int", bson: bson,
- to: 0x7fff_ffff_ffff_ffff)
- {
- try $0["int64"].decode(to: Int.self)
- }
- TestDecoding(tests / "uint64-to-int", bson: bson,
- to: 0x7fff_ffff_ffff_ffff)
- {
- try $0["uint64"].decode(to: Int.self)
- }
- }
-
- if let tests:TestGroup = tests / "tuple"
- {
-
- let bson:BSON.DocumentView<[UInt8]> =
- [
- "none": [],
- "two": ["a", "b"],
- "three": ["a", "b", "c"],
- "four": ["a", "b", "c", "d"],
-
- "heterogenous": ["a", "b", 0, "d"],
- ]
-
- TestDecoding(tests / "none-to-two", bson: bson,
- catching: BSON.DecodingError.init(
- BSON.ShapeError.init(invalid: 0, expected: .length(2)),
- in: "none"))
- {
- try $0["none"].decode
- {
- try $0.shape.expect(length: 2)
- }
- }
-
- TestDecoding(tests / "two-to-two", bson: bson,
- to: ["a", "b"])
- {
- try $0["two"].decode
- {
- try $0.shape.expect(length: 2)
- return try $0.map { try $0.decode(to: String.self) }
- }
- }
-
- TestDecoding(tests / "three-to-two", bson: bson,
- catching: BSON.DecodingError.init(
- BSON.ShapeError.init(invalid: 3, expected: .length(2)),
- in: "three"))
- {
- try $0["three"].decode
- {
- try $0.shape.expect(length: 2)
- }
- }
-
- TestDecoding(tests / "three-by-two", bson: bson,
- catching: BSON.DecodingError.init(
- BSON.ShapeError.init(invalid: 3, expected: .multiple(of: 2)),
- in: "three"))
- {
- try $0["three"].decode
- {
- try $0.shape.expect(multipleOf: 2)
- }
- }
-
- TestDecoding(tests / "four-by-two", bson: bson,
- to: ["a", "b", "c", "d"])
- {
- try $0["four"].decode
- {
- try $0.shape.expect(multipleOf: 2)
- return try $0.map { try $0.decode(to: String.self) }
- }
- }
-
- TestDecoding(tests / "map", bson: bson,
- to: ["a", "b", "c", "d"])
- {
- try $0["four"].decode(to: [String].self)
- }
-
- TestDecoding(tests / "map-invalid", bson: bson,
- catching: BSON.DecodingError.init(
- BSON.DecodingError.init(
- BSON.TypecastError>>.init(
- invalid: .int32),
- in: 2),
- in: "heterogenous"))
- {
- try $0["heterogenous"].decode(to: [String].self)
- }
-
- TestDecoding(tests / "element", bson: bson, to: "c")
- {
- try $0["four"].decode
- {
- try $0.shape.expect { 2 < $0 }
- return try $0[2].decode(to: String.self)
- }
- }
-
- TestDecoding(tests / "element-invalid", bson: bson,
- catching: BSON.DecodingError.init(
- BSON.DecodingError.init(
- BSON.TypecastError>>.init(
- invalid: .int32),
- in: 2),
- in: "heterogenous"))
- {
- try $0["heterogenous"].decode
- {
- try $0.shape.expect { 2 < $0 }
- return try $0[2].decode(to: String.self)
- }
- }
- }
-
- if let tests:TestGroup = tests / "document"
- {
-
- let degenerate:BSON.DocumentView<[UInt8]> =
- [
- "present": .null,
- "present": true,
- ]
- let bson:BSON.DocumentView<[UInt8]> =
- [
- "present": .null,
- "inhabited": true,
- ]
-
- TestDecoding(tests / "key-not-unique", bson: degenerate,
- catching: BSON.DocumentKeyError.duplicate("present"))
- {
- try $0["not-present"].decode(to: Bool.self)
- }
-
- TestDecoding(tests / "key-not-present", bson: bson,
- catching: BSON.DocumentKeyError.undefined("not-present"))
- {
- try $0["not-present"].decode(to: Bool.self)
- }
-
- TestDecoding(tests / "key-matching", bson: bson,
- to: true)
- {
- try $0["inhabited"].decode(to: Bool.self)
- }
-
- TestDecoding(tests / "key-not-matching", bson: bson,
- catching: BSON.DecodingError.init(
- BSON.TypecastError>>.init(invalid: .bool),
- in: "inhabited"))
- {
- try $0["inhabited"].decode(to: String.self)
- }
-
- TestDecoding(tests / "key-not-matching-inhabited", bson: bson,
- catching: BSON.DecodingError.init(
- BSON.TypecastError.init(invalid: .null),
- in: "present"))
- {
- try $0["present"].decode(to: Bool.self)
- }
-
- TestDecoding(tests / "key-inhabited", bson: bson,
- to: .some(true))
- {
- try $0["inhabited"].decode(to: Bool?.self)
- }
-
- TestDecoding(tests / "key-null", bson: bson,
- to: nil)
- {
- try $0["present"].decode(to: Bool?.self)
- }
-
- TestDecoding(tests / "key-optional", bson: bson,
- to: nil)
- {
- try $0["not-present"]?.decode(to: Bool.self)
- }
-
- TestDecoding(tests / "key-optional-null", bson: bson,
- to: .some(.none))
- {
- try $0["present"]?.decode(to: Bool?.self)
- }
-
- TestDecoding(tests / "key-optional-inhabited", bson: bson,
- to: .some(.some(true)))
- {
- try $0["inhabited"]?.decode(to: Bool?.self)
- }
-
- // should throw an error instead of returning [`nil`]().
- TestDecoding(tests / "key-optional-not-inhabited", bson: bson,
- catching: BSON.DecodingError.init(
- BSON.TypecastError.init(invalid: .null),
- in: "present"))
- {
- try $0["present"]?.decode(to: Bool.self)
- }
- }
-
- if let tests:TestGroup = tests / "binary" / "md5"
- {
-
- let md5:BSON.BinaryView<[UInt8]> = .init(subtype: .md5,
- slice: [0xff, 0xfe, 0xfd])
- let bson:BSON.DocumentView<[UInt8]> =
- [
- "md5": .binary(md5),
- ]
-
- tests.do
- {
- let bson:BSON.DocumentDecoder = try .init(
- parsing: bson)
- let decoded:BSON.BinaryView> = try bson["md5"].decode(
- as: BSON.BinaryView>.self)
- {
- $0
- }
- tests.expect(true: md5 == decoded)
- }
- }
-
- if let tests:TestGroup = tests / "losslessstringconvertible"
- {
-
- let bson:BSON.DocumentView<[UInt8]> =
- [
- "string": "e\u{0301}e\u{0301}",
- "character": "e\u{0301}",
- "unicode-scalar": "e",
- ]
-
- TestDecoding(tests / "unicode-scalar-from-string", bson: bson,
- catching: BSON.DecodingError.init(
- BSON.ValueError.init(invalid: "e\u{0301}e\u{0301}"),
- in: "string"))
- {
- try $0["string"].decode(to: Unicode.Scalar.self)
- }
- TestDecoding(tests / "unicode-scalar-from-character", bson: bson,
- catching: BSON.DecodingError.init(
- BSON.ValueError.init(invalid: "e\u{0301}"),
- in: "character"))
- {
- try $0["character"].decode(to: Unicode.Scalar.self)
- }
- TestDecoding(tests / "unicode-scalar", bson: bson,
- to: "e")
- {
- try $0["unicode-scalar"].decode(to: Unicode.Scalar.self)
- }
-
- TestDecoding(tests / "character-from-string", bson: bson,
- catching: BSON.DecodingError.init(
- BSON.ValueError.init(invalid: "e\u{0301}e\u{0301}"),
- in: "string"))
- {
- try $0["string"].decode(to: Character.self)
- }
- TestDecoding(tests / "character", bson: bson,
- to: "e\u{0301}")
- {
- try $0["character"].decode(to: Character.self)
- }
-
- TestDecoding(tests / "string", bson: bson,
- to: "e\u{0301}e\u{0301}")
- {
- try $0["string"].decode(to: String.self)
- }
- }
- }
+ let all:[any TestBattery.Type] =
+ [
+ DecodeBinary.self,
+ DecodeDocument.self,
+ DecodeList.self,
+ DecodeNumeric.self,
+ DecodeString.self,
+ DecodeVoid.self,
+ ]
}
diff --git a/Sources/BSONDecodingTests/TestBattery (ext).swift b/Sources/BSONDecodingTests/TestBattery (ext).swift
new file mode 100644
index 00000000..527529e9
--- /dev/null
+++ b/Sources/BSONDecodingTests/TestBattery (ext).swift
@@ -0,0 +1,32 @@
+import BSONDecoding
+import Testing
+
+extension TestBattery
+{
+ static
+ func run(_ tests:TestGroup?, bson:BSON.DocumentView<[UInt8]>,
+ catching error:Failure,
+ with decode:(BSON.DocumentDecoder) throws -> Unexpected)
+ where Failure:Equatable & Error
+ {
+ tests?.do(catching: error)
+ {
+ _ = try decode(try .init(parsing: bson))
+ }
+ }
+ static
+ func run(_ tests:TestGroup?, bson:BSON.DocumentView<[UInt8]>,
+ to expected:Decoded,
+ with decode:(BSON.DocumentDecoder) throws -> Decoded)
+ where Decoded:Equatable
+ {
+ if let tests:TestGroup
+ {
+ tests.do
+ {
+ let decoded:Decoded = try decode(try .init(parsing: bson))
+ tests.expect(expected ==? decoded)
+ }
+ }
+ }
+}
diff --git a/Sources/BSONDecodingTests/TestDecoding.swift b/Sources/BSONDecodingTests/TestDecoding.swift
deleted file mode 100644
index a0a9b153..00000000
--- a/Sources/BSONDecodingTests/TestDecoding.swift
+++ /dev/null
@@ -1,27 +0,0 @@
-import BSONDecoding
-import Testing
-
-func TestDecoding(_ tests:TestGroup?, bson:BSON.DocumentView<[UInt8]>,
- catching error:Failure,
- with decode:(BSON.DocumentDecoder) throws -> Unexpected)
- where Failure:Equatable & Error
-{
- tests?.do(catching: error)
- {
- _ = try decode(try .init(parsing: bson))
- }
-}
-func TestDecoding(_ tests:TestGroup?, bson:BSON.DocumentView<[UInt8]>,
- to expected:Decoded,
- with decode:(BSON.DocumentDecoder) throws -> Decoded)
- where Decoded:Equatable
-{
- if let tests:TestGroup
- {
- tests.do
- {
- let decoded:Decoded = try decode(try .init(parsing: bson))
- tests.expect(expected ==? decoded)
- }
- }
-}
diff --git a/Sources/BSONEncoding/Dictionary (ext).swift b/Sources/BSONEncoding/Dictionary (ext).swift
index d8b6957f..813e3933 100644
--- a/Sources/BSONEncoding/Dictionary (ext).swift
+++ b/Sources/BSONEncoding/Dictionary (ext).swift
@@ -4,7 +4,7 @@ extension [String: Never]:BSONEncodable
{
/// Encodes this dictionary as an empty document.
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(document: .init(slice: []))
}
diff --git a/Sources/BSONEncoding/Encodability/BSONDocumentEncodable.swift b/Sources/BSONEncoding/Encodability/BSONDocumentEncodable.swift
index 01003b1a..c4375b0b 100644
--- a/Sources/BSONEncoding/Encodability/BSONDocumentEncodable.swift
+++ b/Sources/BSONEncoding/Encodability/BSONDocumentEncodable.swift
@@ -21,7 +21,7 @@ protocol BSONDocumentEncodable:BSONEncodable
extension BSONDocumentEncodable
{
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
self.encode(to: &field[as: BSON.DocumentEncoder.self])
}
diff --git a/Sources/BSONEncoding/Encodability/BSONEncodable.swift b/Sources/BSONEncoding/Encodability/BSONEncodable.swift
index 871e0129..1532318f 100644
--- a/Sources/BSONEncoding/Encodability/BSONEncodable.swift
+++ b/Sources/BSONEncoding/Encodability/BSONEncodable.swift
@@ -1,22 +1,25 @@
+import BSONABI
+
/// A type that can be encoded to a BSON variant value.
public
protocol BSONEncodable
{
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
}
extension BSONEncodable where Self:BSONRepresentable, BSONRepresentation:BSONEncodable
{
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
self.bson.encode(to: &field)
}
}
extension BSONEncodable where Self:RawRepresentable, RawValue:BSONEncodable
{
- /// Returns the ``encode(to:)`` witness of this type’s ``RawRepresentable.rawValue``.
+ /// Returns the ``encode(to:) [7NT06]`` witness of this type’s
+ /// ``RawRepresentable/rawValue``.
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
self.rawValue.encode(to: &field)
}
@@ -81,9 +84,9 @@ extension BSONEncodable where Self == BSON.List
message: "UInt64 is not recommended for BSON that will be handled by MongoDB.")
extension UInt64:BSONEncodable
{
- /// Encodes this integer as a value of type ``BSON.uint64``.
+ /// Encodes this integer as a value of type ``BSON.AnyType/uint64``.
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(uint64: self)
}
@@ -92,9 +95,9 @@ extension UInt64:BSONEncodable
message: "UInt is not recommended for BSON that will be handled by MongoDB.")
extension UInt:BSONEncodable
{
- /// Encodes this integer as a value of type ``BSON.uint64``.
+ /// Encodes this integer as a value of type ``BSON.AnyType/uint64``.
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(uint64: .init(self))
}
diff --git a/Sources/BSONEncoding/Encodability/BSONListEncodable.swift b/Sources/BSONEncoding/Encodability/BSONListEncodable.swift
index 085b26b0..4c0451a0 100644
--- a/Sources/BSONEncoding/Encodability/BSONListEncodable.swift
+++ b/Sources/BSONEncoding/Encodability/BSONListEncodable.swift
@@ -26,14 +26,14 @@ protocol BSONListEncodable:BSONEncodable
extension BSONListEncodable
{
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
self.encode(to: &field[as: BSON.ListEncoder.self])
}
}
extension BSONListEncodable where Self:Sequence, Element:BSONEncodable
{
- /// Encodes this sequence as a value of type ``BSON.list``.
+ /// Encodes this sequence as a value of type ``BSON.AnyType/list``.
@inlinable public
func encode(to bson:inout BSON.ListEncoder)
{
diff --git a/Sources/BSONEncoding/Encodability/BSONStringEncodable.swift b/Sources/BSONEncoding/Encodability/BSONStringEncodable.swift
index fe0d644a..60a060ea 100644
--- a/Sources/BSONEncoding/Encodability/BSONStringEncodable.swift
+++ b/Sources/BSONEncoding/Encodability/BSONStringEncodable.swift
@@ -16,7 +16,7 @@ protocol BSONStringEncodable:BSONEncodable
{
/// Converts an instance of this type to a string. This requirement
/// restates its counterpart in ``LosslessStringConvertible`` if
- /// [`Self`]() also conforms to it.
+ /// `Self` also conforms to it.
var description:String { get }
}
extension BSONStringEncodable
@@ -29,7 +29,7 @@ extension BSONStringEncodable
/// who implement ``LosslessStringConvertible``, but expect to be
/// encoded as something besides a UTF-8 string.
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
self.description.encode(to: &field)
}
diff --git a/Sources/BSONEncoding/Encoding/BSON.Document (ext).swift b/Sources/BSONEncoding/Encoding/BSON.Document (ext).swift
index 07ac596b..3ae7de55 100644
--- a/Sources/BSONEncoding/Encoding/BSON.Document (ext).swift
+++ b/Sources/BSONEncoding/Encoding/BSON.Document (ext).swift
@@ -1,12 +1,12 @@
extension BSON.Document:BSONEncodable
{
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(document: .init(self))
}
}
-extension BSON.Document:BSONBuilder
+extension BSON.Document:_BSONBuilder
{
}
extension BSON.Document
diff --git a/Sources/BSONEncoding/Encoding/BSON.DocumentEncoder.swift b/Sources/BSONEncoding/Encoding/BSON.DocumentEncoder.swift
index f99897e6..76dd4315 100644
--- a/Sources/BSONEncoding/Encoding/BSON.DocumentEncoder.swift
+++ b/Sources/BSONEncoding/Encoding/BSON.DocumentEncoder.swift
@@ -13,19 +13,34 @@ extension BSON
}
}
}
-extension BSON.DocumentEncoder:BSONEncoder
+extension BSON.DocumentEncoder:BSON.Encoder
{
@inlinable public consuming
func move() -> BSON.Output<[UInt8]> { self.output }
@inlinable public static
- var type:BSON { .document }
+ var type:BSON.AnyType { .document }
}
-extension BSON.DocumentEncoder:BSONBuilder
+extension BSON.DocumentEncoder:_BSONBuilder
{
@inlinable public mutating
- func append(_ key:CodingKey, with encode:(inout BSON.Field) -> ())
+ func append(_ key:CodingKey, with encode:(inout BSON.FieldEncoder) -> ())
{
encode(&self.output[with: .init(key)])
}
}
+extension BSON.DocumentEncoder
+{
+ @inlinable public
+ subscript(with key:some RawRepresentable) -> BSON.FieldEncoder
+ {
+ _read
+ {
+ yield self.output[with: .init(key)]
+ }
+ _modify
+ {
+ yield &self.output[with: .init(key)]
+ }
+ }
+}
diff --git a/Sources/BSONEncoding/Encoding/BSON.List (ext).swift b/Sources/BSONEncoding/Encoding/BSON.List (ext).swift
index 943c444f..9377314e 100644
--- a/Sources/BSONEncoding/Encoding/BSON.List (ext).swift
+++ b/Sources/BSONEncoding/Encoding/BSON.List (ext).swift
@@ -1,7 +1,7 @@
extension BSON.List:BSONEncodable
{
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(list: .init(self))
}
diff --git a/Sources/BSONEncoding/Encoding/BSON.ListEncoder.swift b/Sources/BSONEncoding/Encoding/BSON.ListEncoder.swift
index aca8cc69..09a8889d 100644
--- a/Sources/BSONEncoding/Encoding/BSON.ListEncoder.swift
+++ b/Sources/BSONEncoding/Encoding/BSON.ListEncoder.swift
@@ -2,10 +2,9 @@ extension BSON
{
/// A type that can encode BSON list elements directly to an output buffer.
///
- /// Unlike ``DocumentEncoder``, which works with ``BSONDocumentEncodable``,
- /// this type currently doesn’t have a companion protocol. That’s because
- /// we currently only use it to bootstrap faster ``BSONWeakEncodable``
- /// conformances for ``Sequence``s.
+ /// Like ``DocumentEncoder``, which works with ``BSONDocumentEncodable``,
+ /// this type has its own companion protocol ``BSONListEncodable``, which is used to
+ /// bootstrap faster ``BSONEncodable`` conformances for ``Sequence``s.
@frozen public
struct ListEncoder
{
@@ -22,18 +21,18 @@ extension BSON
}
}
}
-extension BSON.ListEncoder:BSONEncoder
+extension BSON.ListEncoder:BSON.Encoder
{
@inlinable public consuming
func move() -> BSON.Output<[UInt8]> { self.output }
@inlinable public static
- var type:BSON { .list }
+ var type:BSON.AnyType { .list }
}
extension BSON.ListEncoder
{
@inlinable public mutating
- func append(with encode:(inout BSON.Field) -> ())
+ func append(with encode:(inout BSON.FieldEncoder) -> ())
{
encode(&self.output[with: .init(index: self.count)])
self.count += 1
diff --git a/Sources/BSONEncoding/Encoding/BSONBuilder.swift b/Sources/BSONEncoding/Encoding/_BSONBuilder.swift
similarity index 84%
rename from Sources/BSONEncoding/Encoding/BSONBuilder.swift
rename to Sources/BSONEncoding/Encoding/_BSONBuilder.swift
index 11ca3265..93e29aaa 100644
--- a/Sources/BSONEncoding/Encoding/BSONBuilder.swift
+++ b/Sources/BSONEncoding/Encoding/_BSONBuilder.swift
@@ -1,12 +1,12 @@
public
-protocol BSONBuilder
+protocol _BSONBuilder
{
associatedtype CodingKey
mutating
- func append(_ key:CodingKey, with encode:(inout BSON.Field) -> ())
+ func append(_ key:CodingKey, with encode:(inout BSON.FieldEncoder) -> ())
}
-extension BSONBuilder
+extension _BSONBuilder
{
@inlinable public mutating
func append(_ key:CodingKey, _ value:some BSONEncodable)
@@ -28,7 +28,7 @@ extension BSONBuilder
self.push(key, value as _?)
}
}
-extension BSONBuilder
+extension _BSONBuilder
{
@inlinable public
subscript(key:CodingKey, with encode:(inout BSON.ListEncoder) -> ()) -> Void
@@ -59,7 +59,7 @@ extension BSONBuilder
}
}
-extension BSONBuilder
+extension _BSONBuilder
{
/// Appends the given key-value pair to this document builder, encoding the
/// value as the field value using its ``BSONEncodable`` implementation.
@@ -67,10 +67,10 @@ extension BSONBuilder
/// Type inference will always prefer one of the concretely-typed subscript
/// overloads over this one.
///
- /// The getter always returns [`nil`]().
+ /// The getter always returns nil.
///
- /// Every non-[`nil`]() assignment to this subscript (including mutations
- /// that leave the value in a non-[`nil`]() state after returning) will add
+ /// Every non-nil assignment to this subscript (including mutations
+ /// that leave the value in a non-nil state after returning) will add
/// a new field to the document, even if the key is the same.
@inlinable public
subscript(key:CodingKey) -> Value? where Value:BSONEncodable
diff --git a/Sources/BSONEncoding/Extensions/BSON (ext).swift b/Sources/BSONEncoding/Extensions/BSON (ext).swift
deleted file mode 100644
index 285abcbe..00000000
--- a/Sources/BSONEncoding/Extensions/BSON (ext).swift
+++ /dev/null
@@ -1,9 +0,0 @@
-extension BSON:BSONEncodable
-{
- /// Encodes this metatype as a value of type ``BSON.int32``.
- @inlinable public
- func encode(to field:inout BSON.Field)
- {
- field.encode(int32: .init(self.rawValue))
- }
-}
diff --git a/Sources/BSONEncoding/Extensions/BSON.AnyType (ext).swift b/Sources/BSONEncoding/Extensions/BSON.AnyType (ext).swift
new file mode 100644
index 00000000..4749912b
--- /dev/null
+++ b/Sources/BSONEncoding/Extensions/BSON.AnyType (ext).swift
@@ -0,0 +1,9 @@
+extension BSON.AnyType:BSONEncodable
+{
+ /// Encodes this metatype as a value of type ``BSON.AnyType/int32``.
+ @inlinable public
+ func encode(to field:inout BSON.FieldEncoder)
+ {
+ field.encode(int32: .init(self.rawValue))
+ }
+}
diff --git a/Sources/BSONEncoding/Extensions/BSON.BinaryView (ext).swift b/Sources/BSONEncoding/Extensions/BSON.BinaryView (ext).swift
index e46bb410..96e3d0c8 100644
--- a/Sources/BSONEncoding/Extensions/BSON.BinaryView (ext).swift
+++ b/Sources/BSONEncoding/Extensions/BSON.BinaryView (ext).swift
@@ -1,7 +1,7 @@
extension BSON.BinaryView:BSONEncodable
{
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(binary: self)
}
diff --git a/Sources/BSONEncoding/Extensions/BSON.Decimal128 (ext).swift b/Sources/BSONEncoding/Extensions/BSON.Decimal128 (ext).swift
index 3c167df4..10ba97a9 100644
--- a/Sources/BSONEncoding/Extensions/BSON.Decimal128 (ext).swift
+++ b/Sources/BSONEncoding/Extensions/BSON.Decimal128 (ext).swift
@@ -1,7 +1,7 @@
extension BSON.Decimal128:BSONEncodable
{
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(decimal128: self)
}
diff --git a/Sources/BSONEncoding/Extensions/BSON.DocumentView (ext).swift b/Sources/BSONEncoding/Extensions/BSON.DocumentView (ext).swift
index e54f7e6a..62d452dd 100644
--- a/Sources/BSONEncoding/Extensions/BSON.DocumentView (ext).swift
+++ b/Sources/BSONEncoding/Extensions/BSON.DocumentView (ext).swift
@@ -1,7 +1,7 @@
extension BSON.DocumentView:BSONEncodable
{
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(document: self)
}
diff --git a/Sources/BSONEncoding/Extensions/BSON.Identifier (ext).swift b/Sources/BSONEncoding/Extensions/BSON.Identifier (ext).swift
index 67a050ec..97bc6ad6 100644
--- a/Sources/BSONEncoding/Extensions/BSON.Identifier (ext).swift
+++ b/Sources/BSONEncoding/Extensions/BSON.Identifier (ext).swift
@@ -1,7 +1,7 @@
extension BSON.Identifier:BSONEncodable
{
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(id: self)
}
diff --git a/Sources/BSONEncoding/Extensions/BSON.ListView (ext).swift b/Sources/BSONEncoding/Extensions/BSON.ListView (ext).swift
index 95e578a4..1d60a7bc 100644
--- a/Sources/BSONEncoding/Extensions/BSON.ListView (ext).swift
+++ b/Sources/BSONEncoding/Extensions/BSON.ListView (ext).swift
@@ -1,7 +1,7 @@
extension BSON.ListView:BSONEncodable
{
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(list: self)
}
diff --git a/Sources/BSONEncoding/Extensions/BSON.Max (ext).swift b/Sources/BSONEncoding/Extensions/BSON.Max (ext).swift
index e3739d2a..a62c4195 100644
--- a/Sources/BSONEncoding/Extensions/BSON.Max (ext).swift
+++ b/Sources/BSONEncoding/Extensions/BSON.Max (ext).swift
@@ -1,7 +1,7 @@
extension BSON.Max:BSONEncodable
{
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(max: self)
}
diff --git a/Sources/BSONEncoding/Extensions/BSON.Millisecond (ext).swift b/Sources/BSONEncoding/Extensions/BSON.Millisecond (ext).swift
index 44a99278..ddbccb73 100644
--- a/Sources/BSONEncoding/Extensions/BSON.Millisecond (ext).swift
+++ b/Sources/BSONEncoding/Extensions/BSON.Millisecond (ext).swift
@@ -1,7 +1,7 @@
extension BSON.Millisecond:BSONEncodable
{
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(millisecond: self)
}
diff --git a/Sources/BSONEncoding/Extensions/BSON.Min (ext).swift b/Sources/BSONEncoding/Extensions/BSON.Min (ext).swift
index b76b2099..e851cff6 100644
--- a/Sources/BSONEncoding/Extensions/BSON.Min (ext).swift
+++ b/Sources/BSONEncoding/Extensions/BSON.Min (ext).swift
@@ -1,7 +1,7 @@
extension BSON.Min:BSONEncodable
{
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(min: self)
}
diff --git a/Sources/BSONEncoding/Extensions/BSON.Regex (ext).swift b/Sources/BSONEncoding/Extensions/BSON.Regex (ext).swift
index 600ded27..e7ee82e5 100644
--- a/Sources/BSONEncoding/Extensions/BSON.Regex (ext).swift
+++ b/Sources/BSONEncoding/Extensions/BSON.Regex (ext).swift
@@ -1,8 +1,8 @@
extension BSON.Regex:BSONEncodable
{
- /// Encodes this regex as a value of type ``BSON.regex``.
+ /// Encodes this regex as a value of type ``BSON.AnyType/regex``.
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(regex: self)
}
diff --git a/Sources/BSONEncoding/Extensions/BSON.UTF8View (ext).swift b/Sources/BSONEncoding/Extensions/BSON.UTF8View (ext).swift
index fe70c83d..704a0ca1 100644
--- a/Sources/BSONEncoding/Extensions/BSON.UTF8View (ext).swift
+++ b/Sources/BSONEncoding/Extensions/BSON.UTF8View (ext).swift
@@ -1,8 +1,8 @@
extension BSON.UTF8View:BSONEncodable
{
- /// Encodes this UTF-8 string as a ``BSON.string``.
+ /// Encodes this UTF-8 string as a ``BSON.AnyType/string``.
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(string: self)
}
diff --git a/Sources/BSONEncoding/Extensions/Bool (ext).swift b/Sources/BSONEncoding/Extensions/Bool (ext).swift
index 71f9565c..84eb07a6 100644
--- a/Sources/BSONEncoding/Extensions/Bool (ext).swift
+++ b/Sources/BSONEncoding/Extensions/Bool (ext).swift
@@ -1,7 +1,7 @@
extension Bool:BSONEncodable
{
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(bool: self)
}
diff --git a/Sources/BSONEncoding/Extensions/Character (ext).swift b/Sources/BSONEncoding/Extensions/Character (ext).swift
index ffdf49d1..8c9d358a 100644
--- a/Sources/BSONEncoding/Extensions/Character (ext).swift
+++ b/Sources/BSONEncoding/Extensions/Character (ext).swift
@@ -1,7 +1,7 @@
extension Character:BSONEncodable
{
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
self.description.encode(to: &field)
}
diff --git a/Sources/BSONEncoding/Extensions/Double (ext).swift b/Sources/BSONEncoding/Extensions/Double (ext).swift
index 0e5c4535..6ee73af8 100644
--- a/Sources/BSONEncoding/Extensions/Double (ext).swift
+++ b/Sources/BSONEncoding/Extensions/Double (ext).swift
@@ -1,8 +1,8 @@
extension Double:BSONEncodable
{
- /// Encodes this metatype as a value of type ``BSON.double``.
+ /// Encodes this metatype as a value of type ``BSON.AnyType/double``.
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(double: .init(self))
}
diff --git a/Sources/BSONEncoding/Extensions/Int (ext).swift b/Sources/BSONEncoding/Extensions/Int (ext).swift
index 901bb7fd..8c4b2f2b 100644
--- a/Sources/BSONEncoding/Extensions/Int (ext).swift
+++ b/Sources/BSONEncoding/Extensions/Int (ext).swift
@@ -1,9 +1,9 @@
extension Int:BSONEncodable
{
- /// Encodes this integer as a value of type ``BSON.int32`` if it can be represented
- /// exactly, or ``BSON.int64`` otherwise.
+ /// Encodes this integer as a value of type ``BSON.AnyType/int32`` if it can be represented
+ /// exactly, or ``BSON.AnyType/int64`` otherwise.
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
if let int32:Int32 = .init(exactly: self)
{
diff --git a/Sources/BSONEncoding/Extensions/Int32 (ext).swift b/Sources/BSONEncoding/Extensions/Int32 (ext).swift
index 83368d26..fda34b0c 100644
--- a/Sources/BSONEncoding/Extensions/Int32 (ext).swift
+++ b/Sources/BSONEncoding/Extensions/Int32 (ext).swift
@@ -1,8 +1,8 @@
extension Int32:BSONEncodable
{
- /// Encodes this integer as a value of type ``BSON.int32``.
+ /// Encodes this integer as a value of type ``BSON.AnyType/int32``.
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(int32: self)
}
diff --git a/Sources/BSONEncoding/Extensions/Int64 (ext).swift b/Sources/BSONEncoding/Extensions/Int64 (ext).swift
index 7adcb807..83578959 100644
--- a/Sources/BSONEncoding/Extensions/Int64 (ext).swift
+++ b/Sources/BSONEncoding/Extensions/Int64 (ext).swift
@@ -1,10 +1,10 @@
extension Int64:BSONEncodable
{
- /// Encodes this integer as a value of type ``BSON.int64``. It will always use
- /// the 64-bit representation, even if it would fit in a ``BSON.int32``. To use
+ /// Encodes this integer as a value of type ``BSON.AnyType/int64``. It will always use
+ /// the 64-bit representation, even if it would fit in a ``BSON.AnyType/int32``. To use
/// a variable-length encoding, encode an ``Int`` instead.
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(int64: self)
}
diff --git a/Sources/BSONEncoding/Extensions/Never (ext).swift b/Sources/BSONEncoding/Extensions/Never (ext).swift
index fad013ba..9cd4aa5d 100644
--- a/Sources/BSONEncoding/Extensions/Never (ext).swift
+++ b/Sources/BSONEncoding/Extensions/Never (ext).swift
@@ -2,7 +2,7 @@ extension Never:BSONEncodable
{
/// ``Never`` encodes anything.
@inlinable public
- func encode(to _:inout BSON.Field)
+ func encode(to _:inout BSON.FieldEncoder)
{
}
}
diff --git a/Sources/BSONEncoding/Extensions/StaticString (ext).swift b/Sources/BSONEncoding/Extensions/StaticString (ext).swift
index 84590fcd..665b0513 100644
--- a/Sources/BSONEncoding/Extensions/StaticString (ext).swift
+++ b/Sources/BSONEncoding/Extensions/StaticString (ext).swift
@@ -1,8 +1,8 @@
extension StaticString:BSONEncodable
{
- /// Encodes this string as a value of type ``BSON.string``.
+ /// Encodes this string as a value of type ``BSON.AnyType/string``.
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(string: .init(self))
}
diff --git a/Sources/BSONEncoding/Extensions/String (ext).swift b/Sources/BSONEncoding/Extensions/String (ext).swift
index ce46197f..88d77301 100644
--- a/Sources/BSONEncoding/Extensions/String (ext).swift
+++ b/Sources/BSONEncoding/Extensions/String (ext).swift
@@ -1,8 +1,8 @@
extension String:BSONEncodable
{
- /// Encodes this string as a value of type ``BSON.string``.
+ /// Encodes this string as a value of type ``BSON.AnyType/string``.
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(string: .init(self))
}
diff --git a/Sources/BSONEncoding/Extensions/Substring (ext).swift b/Sources/BSONEncoding/Extensions/Substring (ext).swift
index 457bd60c..ee9b9e81 100644
--- a/Sources/BSONEncoding/Extensions/Substring (ext).swift
+++ b/Sources/BSONEncoding/Extensions/Substring (ext).swift
@@ -1,8 +1,8 @@
extension Substring:BSONEncodable
{
- /// Encodes this substring as a value of type ``BSON.string``.
+ /// Encodes this substring as a value of type ``BSON.AnyType/string``.
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(string: .init(self))
}
diff --git a/Sources/BSONEncoding/Extensions/Unicode.Scalar (ext).swift b/Sources/BSONEncoding/Extensions/Unicode.Scalar (ext).swift
index c03ff36d..011fac44 100644
--- a/Sources/BSONEncoding/Extensions/Unicode.Scalar (ext).swift
+++ b/Sources/BSONEncoding/Extensions/Unicode.Scalar (ext).swift
@@ -1,7 +1,7 @@
extension Unicode.Scalar:BSONEncodable
{
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
self.description.encode(to: &field)
}
diff --git a/Sources/BSONEncoding/Optional (ext).swift b/Sources/BSONEncoding/Optional (ext).swift
index cd5727e7..6c9b197b 100644
--- a/Sources/BSONEncoding/Optional (ext).swift
+++ b/Sources/BSONEncoding/Optional (ext).swift
@@ -1,8 +1,8 @@
extension Optional:BSONEncodable where Wrapped:BSONEncodable
{
- /// Encodes this optional as an explicit ``BSON.null``, if nil.
+ /// Encodes this optional as an explicit ``BSON.AnyType/null``, if nil.
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
if let self:Wrapped
{
diff --git a/Sources/BSONEncoding/README.md b/Sources/BSONEncoding/README.md
new file mode 100644
index 00000000..d099ed1f
--- /dev/null
+++ b/Sources/BSONEncoding/README.md
@@ -0,0 +1 @@
+# ``/BSONEncoding``
diff --git a/Sources/BSONEncoding/exports.swift b/Sources/BSONEncoding/exports.swift
index 16493bb2..39f8f8b5 100644
--- a/Sources/BSONEncoding/exports.swift
+++ b/Sources/BSONEncoding/exports.swift
@@ -1 +1 @@
-@_exported import BSON
+@_exported import enum BSONABI.BSON
diff --git a/Sources/BSONEncodingTests/Fields/Main.FieldDuplication.swift b/Sources/BSONEncodingTests/Fields/Main.FieldDuplication.swift
new file mode 100644
index 00000000..0dcd7ffe
--- /dev/null
+++ b/Sources/BSONEncodingTests/Fields/Main.FieldDuplication.swift
@@ -0,0 +1,29 @@
+import BSONEncoding
+import Testing
+
+extension Main
+{
+ enum FieldDuplication
+ {
+ }
+}
+extension Main.FieldDuplication:TestBattery
+{
+ static
+ func run(tests:TestGroup)
+ {
+ Self.run(tests / "integer",
+ encoded: .init
+ {
+ $0["inhabited"] = 5
+ $0["uninhabited"] = nil as Never??
+ $0["inhabited"] = 7
+ $0["uninhabited"] = nil as Never??
+ },
+ literal:
+ [
+ "inhabited": 5,
+ "inhabited": 7,
+ ])
+ }
+}
diff --git a/Sources/BSONEncodingTests/Fields/Main.FieldElision.swift b/Sources/BSONEncodingTests/Fields/Main.FieldElision.swift
new file mode 100644
index 00000000..f8eaf4d0
--- /dev/null
+++ b/Sources/BSONEncodingTests/Fields/Main.FieldElision.swift
@@ -0,0 +1,52 @@
+import BSONEncoding
+import Testing
+
+extension Main
+{
+ enum FieldElision
+ {
+ }
+}
+extension Main.FieldElision:TestBattery
+{
+ static
+ func run(tests:TestGroup)
+ {
+ let _:BSON.Document = [:]
+
+ Self.run(tests / "null",
+ encoded: .init
+ {
+ $0["elided"] = nil as Never??
+ $0["inhabited"] = (nil as Never?) as Never??
+ },
+ literal:
+ [
+ "inhabited": .null,
+ ])
+
+ Self.run(tests / "integer",
+ encoded: .init
+ {
+ $0["elided"] = nil as Int?
+ $0["inhabited"] = 5
+ },
+ literal:
+ [
+ "inhabited": 5,
+ ])
+
+ Self.run(tests / "optional",
+ encoded: .init
+ {
+ $0["elided"] = nil as Int??
+ $0["inhabited"] = (5 as Int?) as Int??
+ $0["uninhabited"] = (nil as Int?) as Int??
+ },
+ literal:
+ [
+ "inhabited": 5,
+ "uninhabited": .null,
+ ])
+ }
+}
diff --git a/Sources/BSONEncodingTests/Inference/Main.LiteralInference.swift b/Sources/BSONEncodingTests/Inference/Main.LiteralInference.swift
new file mode 100644
index 00000000..034b46f5
--- /dev/null
+++ b/Sources/BSONEncodingTests/Inference/Main.LiteralInference.swift
@@ -0,0 +1,121 @@
+import BSONEncoding
+import Testing
+
+extension Main
+{
+ enum LiteralInference
+ {
+ }
+}
+extension Main.LiteralInference:TestBattery
+{
+ static
+ func run(tests:TestGroup)
+ {
+ Self.run(tests / "integer",
+ encoded: .init
+ {
+ $0["default"] = 1
+ $0["default-long"] = 0x7fff_ffff_ffff_ffff
+ $0["int32"] = 1 as Int32
+ $0["int64"] = 1 as Int64
+ $0["int"] = 1 as Int
+ $0["int-long"] = 0x7fff_ffff_ffff_ffff as Int
+ },
+ literal:
+ [
+ "default": 1,
+ "default-long": 0x7fff_ffff_ffff_ffff,
+ "int32": .int32(1),
+ "int64": .int64(1),
+ "int": .int32(1),
+ "int-long": .int64(0x7fff_ffff_ffff_ffff),
+ ])
+
+ Self.run(tests / "floating-point",
+ encoded: .init
+ {
+ $0["default"] = 1.0
+ $0["a"] = 1.0 as Double
+ },
+ literal:
+ [
+ "default": 1.0,
+ "a": .double(1.0),
+ ])
+
+ Self.run(tests / "string",
+ encoded: .init
+ {
+ $0["a"] = "string"
+ $0["b"] = "string"
+ $0["c"] = "string" as BSON.UTF8View
+ $0["d"] = "string" as BSON.UTF8View
+ },
+ literal:
+ [
+ "a": "string",
+ "b": "string",
+ "c": .string(.init(from: "string")),
+ "d": .string(.init(from: "string")),
+ ])
+
+ Self.run(tests / "optionals",
+ encoded: .init
+ {
+ $0["a"] = [1, nil, 3]
+ $0["b"] = [1, nil, 3]
+ $0["c"] = [1, .null, 3] as BSON.ListView<[UInt8]>
+ $0["d"] = [1, .null, 3] as BSON.ListView<[UInt8]>
+ },
+ literal:
+ [
+ "a": [1, .null, 3],
+ "b": .list([1, .null, 3]),
+ "c": [1, .null, 3],
+ "d": .list([1, .null, 3]),
+ ])
+
+ Self.run(tests / "list",
+ encoded: .init
+ {
+ $0["a"] = [1, 2, 3]
+ $0["b"] = [1, 2, 3]
+ $0["c"] = [1, 2, 3] as BSON.ListView<[UInt8]>
+ $0["d"] = [1, 2, 3] as BSON.ListView<[UInt8]>
+ },
+ literal:
+ [
+ "a": [1, 2, 3],
+ "b": .list([1, 2, 3]),
+ "c": [1, 2, 3],
+ "d": .list([1, 2, 3]),
+ ])
+
+ Self.run(tests / "document",
+ encoded: .init
+ {
+ $0["a"]
+ {
+ $0["a"] = 1
+ $0["b"] = 2
+ $0["c"] = 3
+ }
+ $0["b"]
+ {
+ $0["a"] = 1
+ $0["b"] = 2
+ $0["c"] = 3
+ }
+ $0["c"] = ["a": 1, "b": 2, "c": 3] as BSON.DocumentView<[UInt8]>
+ $0["d"] = ["a": 1, "b": 2, "c": 3] as BSON.DocumentView<[UInt8]>
+ },
+ literal:
+ [
+ "a": ["a": 1, "b": 2, "c": 3],
+ "b": .document(["a": 1, "b": 2, "c": 3]),
+ "c": ["a": 1, "b": 2, "c": 3],
+ "d": .document(["a": 1, "b": 2, "c": 3]),
+ ])
+ }
+}
diff --git a/Sources/BSONEncodingTests/Inference/Main.TypeInference.swift b/Sources/BSONEncodingTests/Inference/Main.TypeInference.swift
new file mode 100644
index 00000000..4ce2bcda
--- /dev/null
+++ b/Sources/BSONEncodingTests/Inference/Main.TypeInference.swift
@@ -0,0 +1,57 @@
+import BSONEncoding
+import Testing
+
+extension Main
+{
+ enum TypeInference
+ {
+ }
+}
+extension Main.TypeInference:TestBattery
+{
+ static
+ func run(tests:TestGroup)
+ {
+ Self.run(tests / "binary",
+ encoded: .init
+ {
+ $0["a"] = BSON.BinaryView<[UInt8]>.init(subtype: .generic,
+ slice: [0xff, 0xff, 0xff])
+ },
+ literal:
+ [
+ "a": .binary(.init(subtype: .generic,
+ slice: [0xff, 0xff, 0xff])),
+ ])
+
+ Self.run(tests / "max",
+ encoded: .init
+ {
+ $0["max"] = BSON.Max.init()
+ },
+ literal:
+ [
+ "max": .max,
+ ])
+
+ Self.run(tests / "min",
+ encoded: .init
+ {
+ $0["min"] = BSON.Min.init()
+ },
+ literal:
+ [
+ "min": .min,
+ ])
+
+ Self.run(tests / "null",
+ encoded: .init
+ {
+ $0["null"] = (nil as Never?) as Never??
+ },
+ literal:
+ [
+ "null": .null,
+ ])
+ }
+}
diff --git a/Sources/BSONEncodingTests/Main.EncodeDocument.swift b/Sources/BSONEncodingTests/Main.EncodeDocument.swift
new file mode 100644
index 00000000..7133f060
--- /dev/null
+++ b/Sources/BSONEncodingTests/Main.EncodeDocument.swift
@@ -0,0 +1,36 @@
+import BSONEncoding
+import Testing
+
+extension Main
+{
+ enum EncodeDocument
+ {
+ }
+}
+extension Main.EncodeDocument:TestBattery
+{
+ static
+ func run(tests:TestGroup)
+ {
+ Self.run(tests,
+ encoded: .init
+ {
+ $0["a"] = [:]
+ $0["b"]
+ {
+ $0["x"] = 1
+ }
+ $0["c"]
+ {
+ $0["x"] = 1
+ $0["y"] = 2
+ }
+ },
+ literal:
+ [
+ "a": [:],
+ "b": ["x": 1],
+ "c": ["x": 1, "y": 2],
+ ])
+ }
+}
diff --git a/Sources/BSONEncodingTests/Main.EncodeList.swift b/Sources/BSONEncodingTests/Main.EncodeList.swift
new file mode 100644
index 00000000..35a45f47
--- /dev/null
+++ b/Sources/BSONEncodingTests/Main.EncodeList.swift
@@ -0,0 +1,34 @@
+import BSONEncoding
+import Testing
+
+extension Main
+{
+ enum EncodeList
+ {
+ }
+}
+extension Main.EncodeList:TestBattery
+{
+ static
+ func run(tests:TestGroup)
+ {
+ Self.run(tests,
+ encoded: .init
+ {
+ $0["a"] = [] as [Never]
+ $0["b"] = [1]
+ $0["c"]
+ {
+ $0.append(1)
+ $0.append("x")
+ $0.append(5.5)
+ }
+ },
+ literal:
+ [
+ "a": [],
+ "b": [1],
+ "c": [1, "x", 5.5],
+ ])
+ }
+}
diff --git a/Sources/BSONEncodingTests/Main.EncodeString.swift b/Sources/BSONEncodingTests/Main.EncodeString.swift
new file mode 100644
index 00000000..c467b3e5
--- /dev/null
+++ b/Sources/BSONEncodingTests/Main.EncodeString.swift
@@ -0,0 +1,29 @@
+import BSONEncoding
+import Testing
+
+extension Main
+{
+ enum EncodeString
+ {
+ }
+}
+extension Main.EncodeString:TestBattery
+{
+ static
+ func run(tests:TestGroup)
+ {
+ Self.run(tests,
+ encoded: .init
+ {
+ $0["a"] = ""
+ $0["b"] = "foo"
+ $0["c"] = "foo\u{0}"
+ },
+ literal:
+ [
+ "a": "",
+ "b": "foo",
+ "c": "foo\u{0}",
+ ])
+ }
+}
diff --git a/Sources/BSONEncodingTests/Main.swift b/Sources/BSONEncodingTests/Main.swift
index 8e46acdb..301cb0e4 100644
--- a/Sources/BSONEncodingTests/Main.swift
+++ b/Sources/BSONEncodingTests/Main.swift
@@ -1,280 +1,19 @@
-import BSONEncoding
import Testing
@main
-enum Main:SyncTests
+enum Main:TestMain
{
static
- func run(tests:Tests)
- {
- if let tests:TestGroup = tests / "literal-inference"
- {
- TestEncoding(tests / "integer",
- encoded: .init
- {
- $0["default"] = 1
- $0["default-long"] = 0x7fff_ffff_ffff_ffff
- $0["int32"] = 1 as Int32
- $0["int64"] = 1 as Int64
- $0["int"] = 1 as Int
- $0["int-long"] = 0x7fff_ffff_ffff_ffff as Int
- },
- literal:
- [
- "default": 1,
- "default-long": 0x7fff_ffff_ffff_ffff,
- "int32": .int32(1),
- "int64": .int64(1),
- "int": .int32(1),
- "int-long": .int64(0x7fff_ffff_ffff_ffff),
- ])
-
- TestEncoding(tests / "floating-point",
- encoded: .init
- {
- $0["default"] = 1.0
- $0["a"] = 1.0 as Double
- },
- literal:
- [
- "default": 1.0,
- "a": .double(1.0),
- ])
-
- TestEncoding(tests / "string",
- encoded: .init
- {
- $0["a"] = "string"
- $0["b"] = "string"
- $0["c"] = "string" as BSON.UTF8View
- $0["d"] = "string" as BSON.UTF8View
- },
- literal:
- [
- "a": "string",
- "b": "string",
- "c": .string(.init(from: "string")),
- "d": .string(.init(from: "string")),
- ])
-
- TestEncoding(tests / "optionals",
- encoded: .init
- {
- $0["a"] = [1, nil, 3]
- $0["b"] = [1, nil, 3]
- $0["c"] = [1, .null, 3] as BSON.ListView<[UInt8]>
- $0["d"] = [1, .null, 3] as BSON.ListView<[UInt8]>
- },
- literal:
- [
- "a": [1, .null, 3],
- "b": .list([1, .null, 3]),
- "c": [1, .null, 3],
- "d": .list([1, .null, 3]),
- ])
-
- TestEncoding(tests / "list",
- encoded: .init
- {
- $0["a"] = [1, 2, 3]
- $0["b"] = [1, 2, 3]
- $0["c"] = [1, 2, 3] as BSON.ListView<[UInt8]>
- $0["d"] = [1, 2, 3] as BSON.ListView<[UInt8]>
- },
- literal:
- [
- "a": [1, 2, 3],
- "b": .list([1, 2, 3]),
- "c": [1, 2, 3],
- "d": .list([1, 2, 3]),
- ])
-
- TestEncoding(tests / "document",
- encoded: .init
- {
- $0["a"]
- {
- $0["a"] = 1
- $0["b"] = 2
- $0["c"] = 3
- }
- $0["b"]
- {
- $0["a"] = 1
- $0["b"] = 2
- $0["c"] = 3
- }
- $0["c"] = ["a": 1, "b": 2, "c": 3] as BSON.DocumentView<[UInt8]>
- $0["d"] = ["a": 1, "b": 2, "c": 3] as BSON.DocumentView<[UInt8]>
- },
- literal:
- [
- "a": ["a": 1, "b": 2, "c": 3],
- "b": .document(["a": 1, "b": 2, "c": 3]),
- "c": ["a": 1, "b": 2, "c": 3],
- "d": .document(["a": 1, "b": 2, "c": 3]),
- ])
- }
- if let tests:TestGroup = tests / "type-inference"
- {
-
- TestEncoding(tests / "binary",
- encoded: .init
- {
- $0["a"] = BSON.BinaryView<[UInt8]>.init(subtype: .generic,
- slice: [0xff, 0xff, 0xff])
- },
- literal:
- [
- "a": .binary(.init(subtype: .generic,
- slice: [0xff, 0xff, 0xff])),
- ])
-
- TestEncoding(tests / "max",
- encoded: .init
- {
- $0["max"] = BSON.Max.init()
- },
- literal:
- [
- "max": .max,
- ])
-
- TestEncoding(tests / "min",
- encoded: .init
- {
- $0["min"] = BSON.Min.init()
- },
- literal:
- [
- "min": .min,
- ])
-
- TestEncoding(tests / "null",
- encoded: .init
- {
- $0["null"] = (nil as Never?) as Never??
- },
- literal:
- [
- "null": .null,
- ])
- }
- if let tests:TestGroup = tests / "string"
- {
- TestEncoding(tests,
- encoded: .init
- {
- $0["a"] = ""
- $0["b"] = "foo"
- $0["c"] = "foo\u{0}"
- },
- literal:
- [
- "a": "",
- "b": "foo",
- "c": "foo\u{0}",
- ])
- }
- if let tests:TestGroup = tests / "array"
- {
- TestEncoding(tests,
- encoded: .init
- {
- $0["a"] = [] as [Never]
- $0["b"] = [1]
- $0["c"]
- {
- $0.append(1)
- $0.append("x")
- $0.append(5.5)
- }
- },
- literal:
- [
- "a": [],
- "b": [1],
- "c": [1, "x", 5.5],
- ])
- }
- if let tests:TestGroup = tests / "document"
- {
- TestEncoding(tests,
- encoded: .init
- {
- $0["a"] = [:]
- $0["b"]
- {
- $0["x"] = 1
- }
- $0["c"]
- {
- $0["x"] = 1
- $0["y"] = 2
- }
- },
- literal:
- [
- "a": [:],
- "b": ["x": 1],
- "c": ["x": 1, "y": 2],
- ])
- }
- if let tests:TestGroup = tests / "elided-fields"
- {
- let _:BSON.Document = [:]
-
- TestEncoding(tests / "null",
- encoded: .init
- {
- $0["elided"] = nil as Never??
- $0["inhabited"] = (nil as Never?) as Never??
- },
- literal:
- [
- "inhabited": .null,
- ])
-
- TestEncoding(tests / "integer",
- encoded: .init
- {
- $0["elided"] = nil as Int?
- $0["inhabited"] = 5
- },
- literal:
- [
- "inhabited": 5,
- ])
-
- TestEncoding(tests / "optional",
- encoded: .init
- {
- $0["elided"] = nil as Int??
- $0["inhabited"] = (5 as Int?) as Int??
- $0["uninhabited"] = (nil as Int?) as Int??
- },
- literal:
- [
- "inhabited": 5,
- "uninhabited": .null,
- ])
- }
- if let tests:TestGroup = tests / "duplicate-fields"
- {
-
- TestEncoding(tests / "integer",
- encoded: .init
- {
- $0["inhabited"] = 5
- $0["uninhabited"] = nil as Never??
- $0["inhabited"] = 7
- $0["uninhabited"] = nil as Never??
- },
- literal:
- [
- "inhabited": 5,
- "inhabited": 7,
- ])
- }
- }
+ let all:[any TestBattery.Type] =
+ [
+ LiteralInference.self,
+ TypeInference.self,
+
+ EncodeDocument.self,
+ EncodeList.self,
+ EncodeString.self,
+
+ FieldDuplication.self,
+ FieldElision.self,
+ ]
}
diff --git a/Sources/BSONEncodingTests/TestBattery (ext).swift b/Sources/BSONEncodingTests/TestBattery (ext).swift
new file mode 100644
index 00000000..64fd7ee2
--- /dev/null
+++ b/Sources/BSONEncodingTests/TestBattery (ext).swift
@@ -0,0 +1,34 @@
+import BSONEncoding
+import Testing
+
+extension TestBattery
+{
+ static
+ func run(_ tests:TestGroup?,
+ encoded:BSON.Document,
+ literal:BSON.DocumentView<[UInt8]>)
+ {
+ guard
+ let tests:TestGroup
+ else
+ {
+ return
+ }
+
+ let encoded:BSON.DocumentView<[UInt8]> = .init(encoded)
+
+ tests.expect(encoded ==? literal)
+
+ guard let encoded:[(key:BSON.Key, value:BSON.AnyValue>)] =
+ tests.do({ try encoded.parse { ($0, $1) } }),
+ let literal:[(key:BSON.Key, value:BSON.AnyValue>)] =
+ tests.do({ try literal.parse { ($0, $1) } })
+ else
+ {
+ return
+ }
+
+ tests.expect(encoded.map(\.key) ..? literal.map(\.key))
+ tests.expect(encoded.map(\.value) ..? literal.map(\.value))
+ }
+}
diff --git a/Sources/BSONEncodingTests/TestEncoding.swift b/Sources/BSONEncodingTests/TestEncoding.swift
deleted file mode 100644
index 236a83c2..00000000
--- a/Sources/BSONEncodingTests/TestEncoding.swift
+++ /dev/null
@@ -1,29 +0,0 @@
-import BSONEncoding
-import Testing
-
-func TestEncoding(_ tests:TestGroup?,
- encoded:BSON.Document,
- literal:BSON.DocumentView<[UInt8]>)
-{
- guard let tests:TestGroup
- else
- {
- return
- }
-
- let encoded:BSON.DocumentView<[UInt8]> = .init(encoded)
-
- tests.expect(encoded ==? literal)
-
- guard let encoded:[(key:BSON.Key, value:BSON.AnyValue>)] =
- tests.do({ try encoded.parse { ($0, $1) } }),
- let literal:[(key:BSON.Key, value:BSON.AnyValue>)] =
- tests.do({ try literal.parse { ($0, $1) } })
- else
- {
- return
- }
-
- tests.expect(encoded.map(\.key) ..? literal.map(\.key))
- tests.expect(encoded.map(\.value) ..? literal.map(\.value))
-}
diff --git a/Sources/BSONIntegrationTests/Main.EnumeratedCodingKeys.swift b/Sources/BSONIntegrationTests/Main.EnumeratedCodingKeys.swift
new file mode 100644
index 00000000..3aaecbdd
--- /dev/null
+++ b/Sources/BSONIntegrationTests/Main.EnumeratedCodingKeys.swift
@@ -0,0 +1,81 @@
+import BSON
+import BSONReflection
+import Testing
+
+extension Main
+{
+ enum EnumeratedCodingKeys
+ {
+ }
+}
+extension Main.EnumeratedCodingKeys:TestBattery
+{
+ static
+ func run(tests:TestGroup)
+ {
+ struct Codable:BSONDocumentDecodable, BSONDocumentEncodable, Equatable
+ {
+ enum CodingKey:String, Sendable
+ {
+ case a
+ case b
+ case c
+ }
+
+ let a:Int
+ let b:[Int]
+ let c:[[Int]]
+
+ init(a:Int, b:[Int], c:[[Int]])
+ {
+ self.a = a
+ self.b = b
+ self.c = c
+ }
+
+ init(bson:BSON.DocumentDecoder>)
+ throws
+ {
+ self.a = try bson[.a].decode()
+ self.b = try bson[.b].decode()
+ self.c = try bson[.c].decode()
+ }
+
+ func encode(to bson:inout BSON.DocumentEncoder)
+ {
+ bson[.a] = self.a
+ bson[.b] = self.b
+ bson[.c] = self.c
+ }
+ }
+
+ let expected:Codable = .init(a: 5, b: [5, 6], c: [[5, 6, 7], [8]])
+ let bson:BSON.Document = .init
+ {
+ $0["a"] = 5
+ $0["b"] = [5, 6]
+ $0["c"] = [[5, 6, 7], [8]]
+ $0["d"] = [[[5, 6, 7, 8], [9, 10]], [[11]]]
+ }
+
+ tests.do
+ {
+ let original:BSON.DocumentView = .init(bson)
+ let decoded:Codable = try .init(bson: original)
+
+ tests.expect(decoded ==? expected)
+
+ let encoded:BSON.Document = .init(with: decoded.encode(to:))
+
+ tests.expect(true: encoded.bytes.count < original.slice.count)
+
+ let redecoded:Codable = try .init(bson: .init(encoded))
+
+ tests.expect(redecoded ==? expected)
+
+ let reencoded:BSON.Document = .init(with: redecoded.encode(to:))
+
+ tests.expect(reencoded.bytes ..? encoded.bytes)
+ }
+ }
+}
diff --git a/Sources/BSONIntegrationTests/Main.swift b/Sources/BSONIntegrationTests/Main.swift
index de6b8d04..8b88e3f6 100644
--- a/Sources/BSONIntegrationTests/Main.swift
+++ b/Sources/BSONIntegrationTests/Main.swift
@@ -1,81 +1,8 @@
import Testing
-import BSONReflection
-import BSONDecoding
-import BSONEncoding
@main
-enum Main:SyncTests
+enum Main:TestMain
{
static
- func run(tests:Tests)
- {
- if let tests:TestGroup = tests / "EnumeratedCodingKeys"
- {
- struct Codable:BSONDocumentDecodable, BSONDocumentEncodable, Equatable
- {
- enum CodingKey:String, Sendable
- {
- case a
- case b
- case c
- }
-
- let a:Int
- let b:[Int]
- let c:[[Int]]
-
- init(a:Int, b:[Int], c:[[Int]])
- {
- self.a = a
- self.b = b
- self.c = c
- }
-
- init(bson:BSON.DocumentDecoder>)
- throws
- {
- self.a = try bson[.a].decode()
- self.b = try bson[.b].decode()
- self.c = try bson[.c].decode()
- }
-
- func encode(to bson:inout BSON.DocumentEncoder)
- {
- bson[.a] = self.a
- bson[.b] = self.b
- bson[.c] = self.c
- }
- }
-
- let expected:Codable = .init(a: 5, b: [5, 6], c: [[5, 6, 7], [8]])
- let bson:BSON.Document = .init
- {
- $0["a"] = 5
- $0["b"] = [5, 6]
- $0["c"] = [[5, 6, 7], [8]]
- $0["d"] = [[[5, 6, 7, 8], [9, 10]], [[11]]]
- }
-
- tests.do
- {
- let original:BSON.DocumentView = .init(bson)
- let decoded:Codable = try .init(bson: original)
-
- tests.expect(decoded ==? expected)
-
- let encoded:BSON.Document = .init(with: decoded.encode(to:))
-
- tests.expect(true: encoded.bytes.count < original.slice.count)
-
- let redecoded:Codable = try .init(bson: .init(encoded))
-
- tests.expect(redecoded ==? expected)
-
- let reencoded:BSON.Document = .init(with: redecoded.encode(to:))
-
- tests.expect(reencoded.bytes ..? encoded.bytes)
- }
-
- }
- }
+ let all:[any TestBattery.Type] = [EnumeratedCodingKeys.self]
}
diff --git a/Sources/BSONReflection/BSON.AnyValue (ext).swift b/Sources/BSONReflection/BSON.AnyValue (ext).swift
index 057d6449..265cfdf2 100644
--- a/Sources/BSONReflection/BSON.AnyValue (ext).swift
+++ b/Sources/BSONReflection/BSON.AnyValue (ext).swift
@@ -7,43 +7,43 @@ extension BSON.AnyValue
switch self
{
case .document(let document):
- return document.description(indent: indent)
+ document.description(indent: indent)
case .list(let list):
- return list.description(indent: indent)
+ list.description(indent: indent)
case .binary(let binary):
- return "{ binary data, type \(binary.subtype.rawValue) }"
+ "{ binary data, type \(binary.subtype.rawValue) }"
case .bool(let bool):
- return "\(bool)"
+ "\(bool)"
case .decimal128(let decimal128):
- return "\(decimal128) as BSON.Decimal128"
+ "\(decimal128) as BSON.Decimal128"
case .double(let double):
- return "\(double)"
+ "\(double)"
case .id(let id):
- return "\(id)"
+ "\(id)"
case .int32(let int32):
- return "\(int32)"
+ "\(int32)"
case .int64(let int64):
- return "\(int64) as Int64"
+ "\(int64) as Int64"
case .javascript(let javascript):
- return "'\(javascript)'"
+ "'\(javascript)'"
case .javascriptScope(_, _):
- return "{ javascript with scope }"
+ "{ javascript with scope }"
case .max:
- return "max"
+ "max"
case .millisecond(let millisecond):
- return "\(millisecond.value) as BSON.Millisecond"
+ "\(millisecond.value) as BSON.Millisecond"
case .min:
- return "min"
+ "min"
case .null:
- return "null"
+ "null"
case .pointer(let database, let id):
- return "\(database) + \(id)"
+ "\(database) + \(id)"
case .regex(let regex):
- return "\(regex)"
+ "\(regex)"
case .string(let utf8):
- return "\"\(utf8)\""
+ "\"\(utf8)\""
case .uint64(let uint64):
- return "\(uint64) as UInt64"
+ "\(uint64) as UInt64"
}
}
}
@@ -82,46 +82,46 @@ extension BSON.AnyValue
switch (lhs, rhs)
{
case (.document (let lhs), .document (let rhs)):
- return lhs ~~ rhs
+ lhs ~~ rhs
case (.list (let lhs), .list (let rhs)):
- return lhs ~~ rhs
+ lhs ~~ rhs
case (.binary (let lhs), .binary (let rhs)):
- return lhs == rhs
+ lhs == rhs
case (.bool (let lhs), .bool (let rhs)):
- return lhs == rhs
+ lhs == rhs
case (.decimal128 (let lhs), .decimal128 (let rhs)):
- return lhs == rhs
+ lhs == rhs
case (.double (let lhs), .double (let rhs)):
- return lhs == rhs
+ lhs == rhs
case (.id (let lhs), .id (let rhs)):
- return lhs == rhs
+ lhs == rhs
case (.int32 (let lhs), .int32 (let rhs)):
- return lhs == rhs
+ lhs == rhs
case (.int64 (let lhs), .int64 (let rhs)):
- return lhs == rhs
+ lhs == rhs
case (.javascript (let lhs), .javascript (let rhs)):
- return lhs == rhs
+ lhs == rhs
case (.javascriptScope(let lhs, let lhsCode), .javascriptScope(let rhs, let rhsCode)):
- return lhsCode == rhsCode && lhs ~~ rhs
+ lhsCode == rhsCode && lhs ~~ rhs
case (.max, .max):
- return true
+ true
case (.millisecond (let lhs), .millisecond (let rhs)):
- return lhs.value == rhs.value
+ lhs.value == rhs.value
case (.min, .min):
- return true
+ true
case (.null, .null):
- return true
+ true
case (.pointer(let lhs, let lhsID), .pointer(let rhs, let rhsID)):
- return lhsID == rhsID && lhs == rhs
+ lhsID == rhsID && lhs == rhs
case (.regex (let lhs), .regex (let rhs)):
- return lhs == rhs
+ lhs == rhs
case (.string (let lhs), .string (let rhs)):
- return lhs == rhs
+ lhs == rhs
case (.uint64 (let lhs), .uint64 (let rhs)):
- return lhs == rhs
+ lhs == rhs
default:
- return false
+ false
}
}
}
@@ -138,9 +138,9 @@ extension BSON.AnyValue
switch self
{
case .document(let document):
- return .document(try document.canonicalized())
+ .document(try document.canonicalized())
case .list(let list):
- return .list(try list.canonicalized())
+ .list(try list.canonicalized())
case .binary,
.bool,
.decimal128,
@@ -149,9 +149,9 @@ extension BSON.AnyValue
.int32,
.int64,
.javascript:
- return self
+ self
case .javascriptScope(let scope, let utf8):
- return .javascriptScope(try scope.canonicalized(), utf8)
+ .javascriptScope(try scope.canonicalized(), utf8)
case .max,
.millisecond,
.min,
@@ -160,7 +160,7 @@ extension BSON.AnyValue
.regex,
.string,
.uint64:
- return self
+ self
}
}
}
diff --git a/Sources/BSONReflection/BSON.DocumentView (ext).swift b/Sources/BSONReflection/BSON.DocumentView (ext).swift
index 85672869..11644c71 100644
--- a/Sources/BSONReflection/BSON.DocumentView (ext).swift
+++ b/Sources/BSONReflection/BSON.DocumentView (ext).swift
@@ -37,7 +37,7 @@ extension BSON.DocumentView
/// Some documents that do not compare equal under byte-wise
/// `==` comparison may compare equal under this operator, due to normalization
/// of deprecated BSON variants. For example, a value of the deprecated `symbol` type
- /// will compare equal to a ``BSON Value.string(_:)`` value with the same contents.
+ /// will compare equal to a ``BSON.AnyValue/string(_:)`` value with the same contents.
@inlinable public static
func ~~ (lhs:Self, rhs:BSON.DocumentView) -> Bool
{
diff --git a/Sources/BSONReflection/BSON.ListView (ext).swift b/Sources/BSONReflection/BSON.ListView (ext).swift
index 85c62b03..838cf969 100644
--- a/Sources/BSONReflection/BSON.ListView (ext).swift
+++ b/Sources/BSONReflection/BSON.ListView (ext).swift
@@ -15,7 +15,7 @@ extension BSON.ListView:CustomStringConvertible
extension BSON.ListView
{
/// Performs a type-aware equivalence comparison by parsing each operand and recursively
- /// comparing the elements, ignoring list key names. Returns [`false`]() if either
+ /// comparing the elements, ignoring list key names. Returns `false` if either
/// operand fails to parse.
///
/// Some embedded documents that do not compare equal under byte-wise
diff --git a/Sources/BSONReflectionTests/Main.Documents.swift b/Sources/BSONReflectionTests/Main.Documents.swift
new file mode 100644
index 00000000..fe39fbe5
--- /dev/null
+++ b/Sources/BSONReflectionTests/Main.Documents.swift
@@ -0,0 +1,256 @@
+import BSON
+import BSONReflection
+import Testing
+
+extension Main
+{
+ enum Documents
+ {
+ }
+}
+extension Main.Documents:TestBattery
+{
+ static
+ func run(tests:TestGroup)
+ {
+ let document:BSON.Document = .init
+ {
+ $0["_id"] = 0x1111_2222_3333_4444_5555_6666 as BSON.Identifier
+ $0["facility"] = "Recreation and Activities Center"
+
+ $0["logo"] = BSON.BinaryView<[UInt8]>.init(
+ subtype: .generic,
+ slice: [1, 2, 3, 4, 5])
+
+ $0["incidents"] = 145
+ $0["averageRating"] = 2.76
+ $0["supervisors"] = ["Barbie", "Midge", "Raquelle"]
+ $0["notes"] = [] as [Never]
+ $0["campaigns"] = [:]
+ $0["complaints"]
+ {
+ $0.append
+ {
+ $0["_id"] = 0x4455_6677_8899_AABB
+ $0["type"] = "property damage"
+ $0["supervisor"] = "Raquelle"
+ $0["status"] = "open"
+ $0["date"]
+ {
+ $0["Y"] = 2022
+ $0["M"] = 12
+ $0["D"] = 31
+ }
+ }
+ $0.append
+ {
+ $0["_id"] = 0x4455_6677_8899_AABC
+ $0["type"] = "sexual assault"
+ $0["supervisor"] = "Midge"
+ $0["status"] = "open"
+ $0["rpi"] = true
+ $0["date"]
+ {
+ $0["Y"] = 2023
+ $0["M"] = 1
+ $0["D"] = 1
+ }
+ }
+ $0.append
+ {
+ $0["_id"] = 0x4455_6677_8899_AABD
+ $0["type"] = "property theft"
+ $0["supervisor"] = "Barbie"
+ $0["status"] = "closed"
+ $0["date"]
+ {
+ $0["Y"] = 2023
+ $0["M"] = 1
+ $0["D"] = 4
+ }
+ }
+ $0.append
+ {
+ $0["_id"] = 0x4455_6677_8899_AABE
+ $0["type"] = "property damage"
+ $0["supervisor"] = "Midge"
+ $0["status"] = "open"
+ $0["date"]
+ {
+ $0["Y"] = 2023
+ $0["M"] = 1
+ $0["D"] = 16
+ }
+ }
+ $0.append
+ {
+ $0["_id"] = 0x4455_6677_8899_AABF
+ $0["type"] = "assault"
+ $0["supervisor"] = "Raquelle"
+ $0["status"] = "closed"
+ $0["rpi"] = false
+ $0["date"]
+ {
+ $0["Y"] = 2023
+ $0["M"] = 1
+ $0["D"] = 22
+ }
+ }
+ $0.append
+ {
+ $0["_id"] = 0x4455_6677_8899_AAC0
+ $0["type"] = "guest expulsion"
+ $0["supervisor"] = "Barbie"
+ $0["status"] = "closed"
+ $0["rpi"] = true
+ $0["date"]
+ {
+ $0["Y"] = 2023
+ $0["M"] = 2
+ $0["D"] = 14
+ }
+ }
+ $0.append
+ {
+ $0["_id"] = 0x4455_6677_8899_AAC1
+ $0["type"] = "sexual assault"
+ $0["supervisor"] = "Barbie"
+ $0["status"] = "open"
+ $0["rpi"] = false
+ $0["date"]
+ {
+ $0["Y"] = 2023
+ $0["M"] = 2
+ $0["D"] = 14
+ }
+ }
+ }
+ }
+ let value:BSON.AnyValue<[UInt8]> = .document(.init(document))
+ let expected:String =
+ """
+ {
+ $0[_id] = 0x11112222_33334444_55556666
+ $0[facility] = "Recreation and Activities Center"
+ $0[logo] = { binary data, type 0 }
+ $0[incidents] = 145
+ $0[averageRating] = 2.76
+ $0[supervisors] =
+ {
+ $0[0] = "Barbie"
+ $0[1] = "Midge"
+ $0[2] = "Raquelle"
+ }
+ $0[notes] = []
+ $0[campaigns] = [:]
+ $0[complaints] =
+ {
+ $0[0] =
+ {
+ $0[_id] = 4923954431178418875 as Int64
+ $0[type] = "property damage"
+ $0[supervisor] = "Raquelle"
+ $0[status] = "open"
+ $0[date] =
+ {
+ $0[Y] = 2022
+ $0[M] = 12
+ $0[D] = 31
+ }
+ }
+ $0[1] =
+ {
+ $0[_id] = 4923954431178418876 as Int64
+ $0[type] = "sexual assault"
+ $0[supervisor] = "Midge"
+ $0[status] = "open"
+ $0[rpi] = true
+ $0[date] =
+ {
+ $0[Y] = 2023
+ $0[M] = 1
+ $0[D] = 1
+ }
+ }
+ $0[2] =
+ {
+ $0[_id] = 4923954431178418877 as Int64
+ $0[type] = "property theft"
+ $0[supervisor] = "Barbie"
+ $0[status] = "closed"
+ $0[date] =
+ {
+ $0[Y] = 2023
+ $0[M] = 1
+ $0[D] = 4
+ }
+ }
+ $0[3] =
+ {
+ $0[_id] = 4923954431178418878 as Int64
+ $0[type] = "property damage"
+ $0[supervisor] = "Midge"
+ $0[status] = "open"
+ $0[date] =
+ {
+ $0[Y] = 2023
+ $0[M] = 1
+ $0[D] = 16
+ }
+ }
+ $0[4] =
+ {
+ $0[_id] = 4923954431178418879 as Int64
+ $0[type] = "assault"
+ $0[supervisor] = "Raquelle"
+ $0[status] = "closed"
+ $0[rpi] = false
+ $0[date] =
+ {
+ $0[Y] = 2023
+ $0[M] = 1
+ $0[D] = 22
+ }
+ }
+ $0[5] =
+ {
+ $0[_id] = 4923954431178418880 as Int64
+ $0[type] = "guest expulsion"
+ $0[supervisor] = "Barbie"
+ $0[status] = "closed"
+ $0[rpi] = true
+ $0[date] =
+ {
+ $0[Y] = 2023
+ $0[M] = 2
+ $0[D] = 14
+ }
+ }
+ $0[6] =
+ {
+ $0[_id] = 4923954431178418881 as Int64
+ $0[type] = "sexual assault"
+ $0[supervisor] = "Barbie"
+ $0[status] = "open"
+ $0[rpi] = false
+ $0[date] =
+ {
+ $0[Y] = 2023
+ $0[M] = 2
+ $0[D] = 14
+ }
+ }
+ }
+ }
+ """
+
+ var l:Int = 0
+ for (line, expected):(Substring, Substring) in zip(
+ "\(value)".split(whereSeparator: \.isNewline),
+ expected.split(whereSeparator: \.isNewline))
+ {
+ l += 1
+ (tests / "Line\(l)")?.expect(line ==? expected)
+ }
+ }
+}
diff --git a/Sources/BSONReflectionTests/Main.swift b/Sources/BSONReflectionTests/Main.swift
index 503e629d..3a646af7 100644
--- a/Sources/BSONReflectionTests/Main.swift
+++ b/Sources/BSONReflectionTests/Main.swift
@@ -1,254 +1,8 @@
-import BSONEncoding
-import BSONReflection
import Testing
@main
-enum Main:SyncTests
+enum Main:TestMain
{
static
- func run(tests:Tests)
- {
- if let tests:TestGroup = tests / "Documents"
- {
- let document:BSON.Document = .init
- {
- $0["_id"] = 0x1111_2222_3333_4444_5555_6666 as BSON.Identifier
- $0["facility"] = "Recreation and Activities Center"
-
- $0["logo"] = BSON.BinaryView<[UInt8]>.init(
- subtype: .generic,
- slice: [1, 2, 3, 4, 5])
-
- $0["incidents"] = 145
- $0["averageRating"] = 2.76
- $0["supervisors"] = ["Barbie", "Midge", "Raquelle"]
- $0["notes"] = [] as [Never]
- $0["campaigns"] = [:]
- $0["complaints"]
- {
- $0.append
- {
- $0["_id"] = 0x4455_6677_8899_AABB
- $0["type"] = "property damage"
- $0["supervisor"] = "Raquelle"
- $0["status"] = "open"
- $0["date"]
- {
- $0["Y"] = 2022
- $0["M"] = 12
- $0["D"] = 31
- }
- }
- $0.append
- {
- $0["_id"] = 0x4455_6677_8899_AABC
- $0["type"] = "sexual assault"
- $0["supervisor"] = "Midge"
- $0["status"] = "open"
- $0["rpi"] = true
- $0["date"]
- {
- $0["Y"] = 2023
- $0["M"] = 1
- $0["D"] = 1
- }
- }
- $0.append
- {
- $0["_id"] = 0x4455_6677_8899_AABD
- $0["type"] = "property theft"
- $0["supervisor"] = "Barbie"
- $0["status"] = "closed"
- $0["date"]
- {
- $0["Y"] = 2023
- $0["M"] = 1
- $0["D"] = 4
- }
- }
- $0.append
- {
- $0["_id"] = 0x4455_6677_8899_AABE
- $0["type"] = "property damage"
- $0["supervisor"] = "Midge"
- $0["status"] = "open"
- $0["date"]
- {
- $0["Y"] = 2023
- $0["M"] = 1
- $0["D"] = 16
- }
- }
- $0.append
- {
- $0["_id"] = 0x4455_6677_8899_AABF
- $0["type"] = "assault"
- $0["supervisor"] = "Raquelle"
- $0["status"] = "closed"
- $0["rpi"] = false
- $0["date"]
- {
- $0["Y"] = 2023
- $0["M"] = 1
- $0["D"] = 22
- }
- }
- $0.append
- {
- $0["_id"] = 0x4455_6677_8899_AAC0
- $0["type"] = "guest expulsion"
- $0["supervisor"] = "Barbie"
- $0["status"] = "closed"
- $0["rpi"] = true
- $0["date"]
- {
- $0["Y"] = 2023
- $0["M"] = 2
- $0["D"] = 14
- }
- }
- $0.append
- {
- $0["_id"] = 0x4455_6677_8899_AAC1
- $0["type"] = "sexual assault"
- $0["supervisor"] = "Barbie"
- $0["status"] = "open"
- $0["rpi"] = false
- $0["date"]
- {
- $0["Y"] = 2023
- $0["M"] = 2
- $0["D"] = 14
- }
- }
- }
- }
- let value:BSON.AnyValue<[UInt8]> = .document(.init(document))
- let expected:String =
- """
- {
- $0[_id] = 0x11112222_33334444_55556666
- $0[facility] = "Recreation and Activities Center"
- $0[logo] = { binary data, type 0 }
- $0[incidents] = 145
- $0[averageRating] = 2.76
- $0[supervisors] =
- {
- $0[0] = "Barbie"
- $0[1] = "Midge"
- $0[2] = "Raquelle"
- }
- $0[notes] = []
- $0[campaigns] = [:]
- $0[complaints] =
- {
- $0[0] =
- {
- $0[_id] = 4923954431178418875 as Int64
- $0[type] = "property damage"
- $0[supervisor] = "Raquelle"
- $0[status] = "open"
- $0[date] =
- {
- $0[Y] = 2022
- $0[M] = 12
- $0[D] = 31
- }
- }
- $0[1] =
- {
- $0[_id] = 4923954431178418876 as Int64
- $0[type] = "sexual assault"
- $0[supervisor] = "Midge"
- $0[status] = "open"
- $0[rpi] = true
- $0[date] =
- {
- $0[Y] = 2023
- $0[M] = 1
- $0[D] = 1
- }
- }
- $0[2] =
- {
- $0[_id] = 4923954431178418877 as Int64
- $0[type] = "property theft"
- $0[supervisor] = "Barbie"
- $0[status] = "closed"
- $0[date] =
- {
- $0[Y] = 2023
- $0[M] = 1
- $0[D] = 4
- }
- }
- $0[3] =
- {
- $0[_id] = 4923954431178418878 as Int64
- $0[type] = "property damage"
- $0[supervisor] = "Midge"
- $0[status] = "open"
- $0[date] =
- {
- $0[Y] = 2023
- $0[M] = 1
- $0[D] = 16
- }
- }
- $0[4] =
- {
- $0[_id] = 4923954431178418879 as Int64
- $0[type] = "assault"
- $0[supervisor] = "Raquelle"
- $0[status] = "closed"
- $0[rpi] = false
- $0[date] =
- {
- $0[Y] = 2023
- $0[M] = 1
- $0[D] = 22
- }
- }
- $0[5] =
- {
- $0[_id] = 4923954431178418880 as Int64
- $0[type] = "guest expulsion"
- $0[supervisor] = "Barbie"
- $0[status] = "closed"
- $0[rpi] = true
- $0[date] =
- {
- $0[Y] = 2023
- $0[M] = 2
- $0[D] = 14
- }
- }
- $0[6] =
- {
- $0[_id] = 4923954431178418881 as Int64
- $0[type] = "sexual assault"
- $0[supervisor] = "Barbie"
- $0[status] = "open"
- $0[rpi] = false
- $0[date] =
- {
- $0[Y] = 2023
- $0[M] = 2
- $0[D] = 14
- }
- }
- }
- }
- """
-
- var l:Int = 0
- for (line, expected):(Substring, Substring) in zip(
- "\(value)".split(whereSeparator: \.isNewline),
- expected.split(whereSeparator: \.isNewline))
- {
- l += 1
- (tests / "Line\(l)")?.expect(line ==? expected)
- }
- }
- }
+ let all:[any TestBattery.Type] = [Documents.self]
}
diff --git a/Sources/BSONStreaming/BSON.AnyValue (ext).swift b/Sources/BSONStreaming/BSON.AnyValue (ext).swift
deleted file mode 100644
index 4cf55a2f..00000000
--- a/Sources/BSONStreaming/BSON.AnyValue (ext).swift
+++ /dev/null
@@ -1,66 +0,0 @@
-import BSONTypes
-
-extension BSON.AnyValue:ExpressibleByStringLiteral,
- ExpressibleByArrayLiteral,
- ExpressibleByExtendedGraphemeClusterLiteral,
- ExpressibleByUnicodeScalarLiteral,
- ExpressibleByDictionaryLiteral
- where Bytes:RangeReplaceableCollection,
- Bytes:RandomAccessCollection,
- Bytes.Index == Int
-{
- @inlinable public
- init(stringLiteral:String)
- {
- self = .string(.init(from: stringLiteral))
- }
- @inlinable public
- init(arrayLiteral:Self...)
- {
- self = .list(.init(elements: arrayLiteral))
- }
- @inlinable public
- init(dictionaryLiteral:(BSON.Key, Self)...)
- {
- self = .document(.init(fields: dictionaryLiteral))
- }
-}
-
-extension BSON.AnyValue:ExpressibleByFloatLiteral
-{
- @inlinable public
- init(floatLiteral:Double)
- {
- self = .double(floatLiteral)
- }
-}
-extension BSON.AnyValue:ExpressibleByIntegerLiteral
-{
- /// Creates an instance initialized to the specified integer value.
- /// It will be an ``int32(_:)`` value if it fits, otherwise it will
- /// be an ``int64(_:)``.
- ///
- /// Although MongoDB uses ``Int32`` as its default integer type,
- /// this library infers integer literals to be of type ``Int`` for
- /// consistency with the rest of the Swift language.
- @inlinable public
- init(integerLiteral:Int)
- {
- if let int32:Int32 = .init(exactly: integerLiteral)
- {
- self = .int32(int32)
- }
- else
- {
- self = .int64(Int64.init(integerLiteral))
- }
- }
-}
-extension BSON.AnyValue:ExpressibleByBooleanLiteral
-{
- @inlinable public
- init(booleanLiteral:Bool)
- {
- self = .bool(booleanLiteral)
- }
-}
diff --git a/Sources/BSONStreaming/BSONDecoder.swift b/Sources/BSONStreaming/BSONDecoder.swift
deleted file mode 100644
index 489d3b8a..00000000
--- a/Sources/BSONStreaming/BSONDecoder.swift
+++ /dev/null
@@ -1,17 +0,0 @@
-import BSONTypes
-
-public
-protocol BSONDecoder
-{
- associatedtype Storage:RandomAccessCollection
-
- init(parsing bson:__shared BSON.AnyValue) throws
-}
-extension BSONDecoder
-{
- /// Ddecoder elements are indices over fragments of BSON
- /// parsed from a larger allocation, like ``Substring``s from a
- /// larger parent ``String``.
- public
- typealias Bytes = Storage.SubSequence
-}
diff --git a/Sources/BSONStreaming/BSONEncoder.swift b/Sources/BSONStreaming/BSONEncoder.swift
deleted file mode 100644
index 104a1417..00000000
--- a/Sources/BSONStreaming/BSONEncoder.swift
+++ /dev/null
@@ -1,13 +0,0 @@
-import BSONTypes
-
-public
-protocol BSONEncoder
-{
- init(_:consuming BSON.Output<[UInt8]>)
-
- consuming
- func move() -> BSON.Output<[UInt8]>
-
- static
- var type:BSON { get }
-}
diff --git a/Sources/BSONTesting/TestGroup (ext).swift b/Sources/BSONTesting/TestGroup (ext).swift
index d0c187fc..f5a13802 100644
--- a/Sources/BSONTesting/TestGroup (ext).swift
+++ b/Sources/BSONTesting/TestGroup (ext).swift
@@ -1,5 +1,4 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
import Testing
extension TestGroup
diff --git a/Sources/BSONTests/Main.InvalidBSON.swift b/Sources/BSONTests/Main.InvalidBSON.swift
new file mode 100644
index 00000000..6603d2c7
--- /dev/null
+++ b/Sources/BSONTests/Main.InvalidBSON.swift
@@ -0,0 +1,329 @@
+import Base16
+import BSON
+import BSONReflection
+import Testing
+
+extension Main
+{
+ enum InvalidBSON
+ {
+ }
+}
+extension Main.InvalidBSON:TestBattery
+{
+ static
+ func run(tests:TestGroup)
+ {
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/boolean.json
+ if let tests:TestGroup = tests / "bool"
+ {
+ Self.run(tests / "invalid-subtype",
+ invalid: "090000000862000200",
+ catching: BSON.BooleanSubtypeError.init(invalid: 2))
+
+ Self.run(tests / "invalid-subtype-negative",
+ invalid: "09000000086200FF00",
+ catching: BSON.BooleanSubtypeError.init(invalid: 255))
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/int32.json
+ if let tests:TestGroup = tests / "int32"
+ {
+ Self.run(tests / "truncated",
+ invalid: "09000000_10_6100_05_00",
+ catching: BSON.InputError.init(expected: .bytes(4), encountered: 1))
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/int32.json
+ if let tests:TestGroup = tests / "int64"
+ {
+ Self.run(tests / "truncated",
+ invalid: "0C000000_12_6100_12345678_00",
+ catching: BSON.InputError.init(expected: .bytes(8), encountered: 4))
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/timestamp.json
+ if let tests:TestGroup = tests / "uint64"
+ {
+ Self.run(tests / "truncated",
+ invalid: "0F000000_11_6100_2A00000015CD5B_00",
+ catching: BSON.InputError.init(expected: .bytes(8), encountered: 7))
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/top.json
+ if let tests:TestGroup = tests / "top"
+ {
+ Self.run(tests / "zeroes",
+ invalid: "00000000_000000000000",
+ // ^~~~~~~~
+ catching: BSON.HeaderError.init(length: 0))
+
+ Self.run(tests / "invalid-length-over",
+ invalid: "12000000_02_666F6F00_04000000_626172",
+ // ^~~~~~~~
+ catching: BSON.InputError.init(expected: .bytes(0x12 - 4), encountered: 12))
+
+ Self.run(tests / "invalid-length-under",
+ invalid: "12000000_02_666F6F00_04000000_62617200_00_DEADBEEF",
+ // ^~~~~~~~
+ catching: BSON.InputError.init(expected: .end, encountered: 4))
+
+ Self.run(tests / "invalid-type-0x00",
+ invalid: "07000000_00_0000",
+ // ^~
+ catching: BSON.TypeError.init(invalid: 0x00))
+
+ Self.run(tests / "invalid-type-0x80",
+ invalid: "07000000_80_0000",
+ // ^~
+ catching: BSON.TypeError.init(invalid: 0x80))
+
+ Self.run(tests / "truncated",
+ invalid: "12000000_02_666F",
+ catching: BSON.InputError.init(expected: .bytes(0x12 - 4), encountered: 3))
+
+ Self.run(tests / "invalid-key",
+ invalid: "0D000000_10_7800_00_0100000000",
+ // ^~
+ catching: BSON.TypeError.init(invalid: 0x00))
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/datetime.json
+ if let tests:TestGroup = tests / "millisecond"
+ {
+ Self.run(tests / "truncated",
+ invalid: "0C000000_0961001234567800",
+ catching: BSON.InputError.init(expected: .bytes(8), encountered: 4))
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/double.json
+ if let tests:TestGroup = tests / "double"
+ {
+ // note: frameshift
+ Self.run(tests / "truncated",
+ invalid: "0B000000_0164000000F03F00",
+ // ^~~~~~~~
+ catching: BSON.InputError.init(expected: .end, encountered: 1))
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/oid.json
+ if let tests:TestGroup = tests / "id"
+ {
+ Self.run(tests / "truncated",
+ invalid: "12000000_07_6100_56E1FC72E0C917E9C471",
+ // ^~~~~~~~
+ catching: BSON.InputError.init(expected: .bytes(0x12 - 4), encountered: 13))
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/dbpointer.json
+ if let tests:TestGroup = tests / "pointer"
+ {
+ Self.run(tests / "invalid-length-negative",
+ invalid: "1A000000_0C_6100_FFFFFFFF_620056E1FC72E0C917E9C471416100",
+ // ^~~~~~~~
+ catching: BSON.HeaderError.init(length: -1))
+
+ Self.run(tests / "invalid-length-zero",
+ invalid: "1A000000_0C_6100_00000000_620056E1FC72E0C917E9C471416100",
+ // ^~~~~~~~
+ catching: BSON.HeaderError.init(length: 0))
+
+ Self.run(tests / "truncated",
+ invalid: "16000000_0C_6100_03000000_616200_56E1FC72E0C91700",
+ catching: BSON.InputError.init(expected: .bytes(12), encountered: 7))
+
+ Self.run(tests / "truncated-identifier",
+ invalid: "1A000000_0C_6100_03000000_616200_56E1FC72E0C917E9C4716100",
+ catching: BSON.InputError.init(expected: .bytes(12), encountered: 11))
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/binary.json
+ if let tests:TestGroup = tests / "binary"
+ {
+ Self.run(tests / "invalid-length-over",
+ invalid: "1D000000_05_7800_FF000000_05_73FFD26444B34C6990E8E7D1DFC035D400",
+ // ^~~~~~~~
+ catching: BSON.InputError.init(expected: .bytes(0xFF + 1), encountered: 17))
+
+ Self.run(tests / "invalid-length-negative",
+ invalid: "0D000000057800FFFFFFFF0000",
+ catching: BSON.BinaryViewError.init(expected: .subtype))
+ // TODO: tests for legacy binary subtype 0x02
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/document.json
+ if let tests:TestGroup = tests / "document"
+ {
+ Self.run(tests / "invalid-length-over",
+ invalid: "18000000_03_666F6F00_0F000000_10_62617200_FFFFFF7F_0000",
+ // ^~~~~~~~
+ catching: BSON.InputError.init(expected: .bytes(0x0F - 4), encountered: 10))
+
+ Self.run(tests / "invalid-length-under",
+ invalid: "15000000_03_666F6F00_0A000000_08_62617200_01_00_00",
+ // ^~
+ catching: BSON.InputError.init(expected: .bytes(1)))
+
+ Self.run(tests / "invalid-value",
+ invalid: "1C000000_03_666F6F00_12000000_02_62617200_05000000_62617A000000",
+ // ^~~~~~~~
+ catching: BSON.InputError.init(expected: .bytes(5), encountered: 4))
+
+ Self.run(tests / "invalid-key",
+ invalid: "15000000_03_7800_0D000000_10_6100_00010000_00_0000",
+ // ^~
+ catching: BSON.TypeError.init(invalid: 0))
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/array.json
+ if let tests:TestGroup = tests / "tuple"
+ {
+ Self.run(tests / "invalid-length-over",
+ invalid: "14000000_04_6100_0D000000_10_30000A00_00_000000",
+ // ^~~~~~~~
+ catching: BSON.InputError.init(expected: .bytes(0x0D - 4), encountered: 8))
+
+ Self.run(tests / "invalid-length-under",
+ invalid: "14000000_04_6100_0B000000_10_30000A00_00_000000",
+ // ^~~~~~~~
+ catching: BSON.InputError.init(expected: .bytes(4), encountered: 3))
+
+ Self.run(tests / "invalid-element",
+ invalid: "1A000000_04_666F6F00_100000000230000500000062617A000000",
+ //
+ catching: BSON.InputError.init(expected: .bytes(5), encountered: 4))
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/regex.json
+ if let tests:TestGroup = tests / "regex"
+ {
+ // note: frameshift
+ Self.run(tests / "invalid-pattern",
+ invalid: "0F0000000B610061006300696D0000",
+ catching: BSON.Regex.OptionError.init(invalid: "c"))
+ // note: frameshift
+ Self.run(tests / "invalid-options",
+ invalid: "100000000B61006162630069006D0000",
+ catching: BSON.TypeError.init(invalid: 109))
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/string.json
+ if let tests:TestGroup = tests / "string"
+ {
+ Self.run(tests / "missing-trailing-null-byte",
+ invalid: "0C000000_02_6100_00000000_00",
+ // ^~~~~~~~
+ catching: BSON.HeaderError.init(length: 0))
+
+ Self.run(tests / "invalid-length-negative",
+ invalid: "0C000000_02_6100_FFFFFFFF_00",
+ // ^~~~~~~~
+ catching: BSON.HeaderError.init(length: -1))
+
+ Self.run(tests / "invalid-length-over",
+ invalid: "10000000_02_6100_05000000_62006200_00",
+ // ^~~~~~~~
+ catching: BSON.InputError.init(expected: .bytes(5), encountered: 4))
+
+ Self.run(tests / "invalid-length-over-document",
+ invalid: "12000000_02_00_FFFFFF00_666F6F6261720000",
+ // ^~~~~~~~
+ catching: BSON.InputError.init(expected: .bytes(0xffffff), encountered: 7))
+
+ Self.run(tests / "invalid-length-under",
+ invalid: "0E000000_02_6100_01000000_00_00_00",
+ // ^~
+ catching: BSON.TypeError.init(invalid: 0x00))
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/code.json
+ if let tests:TestGroup = tests / "javascript"
+ {
+ Self.run(tests / "missing-trailing-null-byte",
+ invalid: "0C000000_0D_6100_00000000_00",
+ // ^~~~~~~~
+ catching: BSON.HeaderError.init(length: 0))
+
+ Self.run(tests / "invalid-length-negative",
+ invalid: "0C0000000D6100FFFFFFFF00",
+ catching: BSON.HeaderError.init(length: -1))
+
+ Self.run(tests / "invalid-length-over",
+ invalid: "10000000_0D_6100_05000000_6200620000",
+ // ^~~~~~~~
+ catching: BSON.InputError.init(expected: .bytes(5), encountered: 4))
+
+ Self.run(tests / "invalid-length-over-document",
+ invalid: "12000000_0D_00_FFFFFF00_666F6F6261720000",
+ // ^~~~~~~~
+ catching: BSON.InputError.init(expected: .bytes(0xffffff), encountered: 7))
+
+ Self.run(tests / "invalid-length-under",
+ invalid: "0E000000_0D_6100_01000000_00_00_00",
+ // ^~
+ catching: BSON.TypeError.init(invalid: 0x00))
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/code_w_scope.json
+ if let tests:TestGroup = tests / "javascript-scope"
+ {
+ // note: we do not validate the redundant field length,
+ // so those tests are not included
+
+ // note: the length is actually too short, but because we use the component-wise
+ // length headers instead of the field length, this manifests itself as a
+ // frameshift error.
+ Self.run(tests / "invalid-length-frameshift-clips-scope",
+ invalid: """
+ 28000000_0F_6100_20000000_04000000_61626364_00130000_0010780001000000107900010000000000
+ """,
+ // ^~~~~~~~
+ catching: BSON.InputError.init(expected: .bytes(0x00_00_13_00 - 4), encountered: 16))
+
+ Self.run(tests / "invalid-length-over",
+ invalid: """
+ 28000000_0F_6100_20000000_06000000_616263640013_00000010_780001000000107900010000000000
+ """,
+ // ^~~~~~~~
+ catching: BSON.InputError.init(expected: .bytes(0x10_00_00_00 - 4), encountered: 14))
+ // note: frameshift
+ Self.run(tests / "invalid-length-frameshift",
+ invalid: """
+ 28000000_0F_6100_20000000_FF000000_61626364001300000010780001000000107900010000000000
+ """,
+ catching: BSON.InputError.init(expected: .bytes(255), encountered: 24))
+
+ Self.run(tests / "invalid-scope",
+ invalid: """
+ 1C000000_0F_00_15000000_01000000_00_0C000000_02_00000000_00000000
+ """,
+ // ^~~~~~~~
+ catching: BSON.HeaderError.init(length: 0))
+ }
+ }
+}
+extension Main.InvalidBSON
+{
+ private static
+ func run(_ tests:TestGroup?, invalid:String, catching error:some Error & Equatable)
+ {
+ guard
+ let tests:TestGroup
+ else
+ {
+ return
+ }
+
+ let invalid:[UInt8] = Base16.decode(invalid.utf8)
+
+ var input:BSON.Input<[UInt8]> = .init(invalid)
+
+ tests.do(catching: error)
+ {
+ let document:BSON.DocumentView> = try input.parse(
+ as: BSON.DocumentView>.self)
+ try input.finish()
+ _ = try document.canonicalized()
+ }
+ }
+}
diff --git a/Sources/BSONTests/Main.ValidBSON.swift b/Sources/BSONTests/Main.ValidBSON.swift
new file mode 100644
index 00000000..6d69265c
--- /dev/null
+++ b/Sources/BSONTests/Main.ValidBSON.swift
@@ -0,0 +1,609 @@
+import Base16
+import BSON
+import BSONReflection
+import Testing
+
+extension Main
+{
+ enum ValidBSON
+ {
+ }
+}
+extension Main.ValidBSON:TestBattery
+{
+ static
+ func run(tests:TestGroup)
+ {
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/multi-type.json
+ // cannot use this test, because it encodes a deprecated binary subtype, which is
+ // (intentionally) impossible to construct with swift-bson.
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/maxkey.json
+ do
+ {
+ Self.run(tests / "max",
+ canonical: "080000007F610000",
+ expected: ["a": .max])
+ }
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/minkey.json
+ do
+ {
+ Self.run(tests / "min",
+ canonical: "08000000FF610000",
+ expected: ["a": .min])
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/null.json
+ do
+ {
+ Self.run(tests / "null",
+ canonical: "080000000A610000",
+ expected: ["a": .null])
+ }
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/undefined.json
+ do
+ {
+ Self.run(tests / "undefined",
+ degenerate: "0800000006610000",
+ canonical: "080000000A610000",
+ expected: ["a": .null])
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/boolean.json
+ if let tests:TestGroup = tests / "bool"
+ {
+ Self.run(tests / "true",
+ canonical: "090000000862000100",
+ expected: ["b": true])
+ Self.run(tests / "false",
+ canonical: "090000000862000000",
+ expected: ["b": false])
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/int32.json
+ if let tests:TestGroup = tests / "int32"
+ {
+ Self.run(tests / "min",
+ canonical: "0C0000001069000000008000",
+ expected: ["i": .int32(-2147483648)])
+
+ Self.run(tests / "max",
+ canonical: "0C000000106900FFFFFF7F00",
+ expected: ["i": .int32(2147483647)])
+
+ Self.run(tests / "-1",
+ canonical: "0C000000106900FFFFFFFF00",
+ expected: ["i": .int32(-1)])
+
+ Self.run(tests / "0",
+ canonical: "0C0000001069000000000000",
+ expected: ["i": .int32(0)])
+
+ Self.run(tests / "+1",
+ canonical: "0C0000001069000100000000",
+ expected: ["i": .int32(1)])
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/int32.json
+ if let tests:TestGroup = tests / "int64"
+ {
+ Self.run(tests / "min",
+ canonical: "10000000126100000000000000008000",
+ expected: ["a": .int64(-9223372036854775808)])
+
+ Self.run(tests / "max",
+ canonical: "10000000126100FFFFFFFFFFFFFF7F00",
+ expected: ["a": .int64(9223372036854775807)])
+
+ Self.run(tests / "-1",
+ canonical: "10000000126100FFFFFFFFFFFFFFFF00",
+ expected: ["a": .int64(-1)])
+
+ Self.run(tests / "0",
+ canonical: "10000000126100000000000000000000",
+ expected: ["a": .int64(0)])
+
+ Self.run(tests / "+1",
+ canonical: "10000000126100010000000000000000",
+ expected: ["a": .int64(1)])
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/timestamp.json
+ if let tests:TestGroup = tests / "uint64"
+ {
+ Self.run(tests / "(123456789, 42)",
+ canonical: "100000001161002A00000015CD5B0700",
+ expected: ["a": .uint64(123456789 << 32 | 42)])
+
+ Self.run(tests / "ones",
+ canonical: "10000000116100FFFFFFFFFFFFFFFF00",
+ expected: ["a": .uint64(.max)])
+
+ Self.run(tests / "(4000000000, 4000000000)",
+ canonical: "1000000011610000286BEE00286BEE00",
+ expected: ["a": .uint64(4000000000 << 32 | 4000000000)])
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/top.json
+ if let tests:TestGroup = tests / "top"
+ {
+ Self.run(tests / "dollar-prefixed-key",
+ canonical: "0F00000010246B6579002A00000000",
+ expected: ["$key": .int32(42)])
+
+ Self.run(tests / "dollar-key",
+ canonical: "0E00000002240002000000610000",
+ expected: ["$": "a"])
+
+ Self.run(tests / "dotted-key",
+ canonical: "1000000002612E620002000000630000",
+ expected: ["a.b": "c"])
+
+ Self.run(tests / "dot-key",
+ canonical: "0E000000022E0002000000610000",
+ expected: [".": "a"])
+
+ Self.run(tests / "empty-truncated-header",
+ degenerate: "0100000000",
+ canonical: "0500000000",
+ expected: [:])
+
+ Self.run(tests / "empty",
+ canonical: "0500000000",
+ expected: [:])
+
+ Self.run(tests / "invalid-end-of-object-0x01",
+ degenerate: "05000000_01",
+ canonical: "05000000_00",
+ expected: [:])
+
+ Self.run(tests / "invalid-end-of-object-0xff",
+ degenerate: "05000000_FF",
+ canonical: "05000000_00",
+ expected: [:])
+
+ Self.run(tests / "invalid-end-of-object-0x70",
+ degenerate: "05000000_70",
+ canonical: "05000000_00",
+ expected: [:])
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/decimal128-1.json
+ if let tests:TestGroup = tests / "decimal128"
+ {
+ Self.run(tests / "positive-quiet-nan",
+ canonical: "180000001364000000000000000000000000000000007C00",
+ expected: ["d": .decimal128(.init(
+ high: 0x7C00_0000_0000_0000,
+ low: 0x0000_0000_0000_0000))])
+
+ Self.run(tests / "negative-quiet-nan",
+ canonical: "18000000136400000000000000000000000000000000FC00",
+ expected: ["d": .decimal128(.init(
+ high: 0xFC00_0000_0000_0000,
+ low: 0x0000_0000_0000_0000))])
+
+ Self.run(tests / "positive-signaling-nan",
+ canonical: "180000001364000000000000000000000000000000007E00",
+ expected: ["d": .decimal128(.init(
+ high: 0x7E00_0000_0000_0000,
+ low: 0x0000_0000_0000_0000))])
+
+ Self.run(tests / "negative-signaling-nan",
+ canonical: "18000000136400000000000000000000000000000000FE00",
+ expected: ["d": .decimal128(.init(
+ high: 0xFE00_0000_0000_0000,
+ low: 0x0000_0000_0000_0000))])
+
+ // this only serves to verify we are handling byte-order correctly;
+ // there is very little point in elaborating decimal128 tests further
+ Self.run(tests / "largest",
+ canonical: "18000000136400F2AF967ED05C82DE3297FF6FDE3C403000",
+ expected: ["d": .decimal128(.init(
+ high: 0x3040_3CDE_6FFF_9732,
+ low: 0xDE82_5CD0_7E96_AFF2))])
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/datetime.json
+ if let tests:TestGroup = tests / "millisecond"
+ {
+ Self.run(tests / "epoch",
+ canonical: "10000000096100000000000000000000",
+ expected: ["a": .millisecond(0)])
+
+ Self.run(tests / "positive",
+ canonical: "10000000096100C5D8D6CC3B01000000",
+ expected: ["a": .millisecond(1356351330501)])
+
+ Self.run(tests / "negative",
+ canonical: "10000000096100C33CE7B9BDFFFFFF00",
+ expected: ["a": .millisecond(-284643869501)])
+
+ Self.run(tests / "positive-2",
+ canonical: "1000000009610000DC1FD277E6000000",
+ expected: ["a": .millisecond(253402300800000)])
+
+ Self.run(tests / "positive-3",
+ canonical: "10000000096100D1D6D6CC3B01000000",
+ expected: ["a": .millisecond(1356351330001)])
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/double.json
+ if let tests:TestGroup = tests / "double"
+ {
+ Self.run(tests / "+1.0",
+ canonical: "10000000016400000000000000F03F00",
+ expected: ["d": .double(1.0)])
+
+ Self.run(tests / "-1.0",
+ canonical: "10000000016400000000000000F0BF00",
+ expected: ["d": .double(-1.0)])
+
+ Self.run(tests / "+1.0001220703125",
+ canonical: "10000000016400000000008000F03F00",
+ expected: ["d": .double(1.0001220703125)])
+
+ Self.run(tests / "-1.0001220703125",
+ canonical: "10000000016400000000008000F0BF00",
+ expected: ["d": .double(-1.0001220703125)])
+
+ Self.run(tests / "1.2345678921232E+18",
+ canonical: "100000000164002a1bf5f41022b14300",
+ expected: ["d": .double(1.2345678921232e18)])
+
+ Self.run(tests / "-1.2345678921232E+18",
+ canonical: "100000000164002a1bf5f41022b1c300",
+ expected: ["d": .double(-1.2345678921232e18)])
+
+ // remaining corpus test cases are pointless because swift cannot distinguish
+ // between -0.0 and +0.0
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/oid.json
+ if let tests:TestGroup = tests / "id"
+ {
+ let id:BSON.Identifier = 0x0123_4567_89AB_CDEF_4567_3210
+
+ tests.expect(id.timestamp ==? 0x0123_4567)
+ tests.expect(true: id.seed == (0x89, 0xAB, 0xCD, 0xEF, 0x45))
+ tests.expect(true: id.ordinal == (0x67, 0x32, 0x10))
+
+ tests.expect(id ==? .init(timestamp: id.timestamp, seed: id.seed, ordinal: id.ordinal))
+
+ Self.run(tests / "zeroes",
+ canonical: "1400000007610000000000000000000000000000",
+ expected: ["a": .id(0x00000000_00000000_00_000000)])
+
+ Self.run(tests / "ones",
+ canonical: "14000000076100FFFFFFFFFFFFFFFFFFFFFFFF00",
+ expected: ["a": .id(0xffffffff_ffffffff_ff_ffffff)])
+
+ Self.run(tests / "random",
+ canonical: "1400000007610056E1FC72E0C917E9C471416100",
+ expected: ["a": .id(0x56e1fc72_e0c917e9_c4_714161)])
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/dbpointer.json
+ if let tests:TestGroup = tests / "pointer"
+ {
+
+ Self.run(tests / "ascii",
+ canonical: "1A0000000C610002000000620056E1FC72E0C917E9C471416100",
+ expected: ["a": .pointer(.init(from: "b"), .init(
+ 0x56e1fc72, 0xe0c917e9, 0xc4_714161))])
+
+ Self.run(tests / "unicode",
+ canonical: "1B0000000C610003000000C3A90056E1FC72E0C917E9C471416100",
+ expected: ["a": .pointer(.init(from: "é"), .init(
+ 0x56e1fc72, 0xe0c917e9, 0xc4_714161))])
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/binary.json
+ if let tests:TestGroup = tests / "binary"
+ {
+ Self.run(tests / "generic-empty",
+ canonical: "0D000000057800000000000000",
+ expected: ["x": .binary(.init(subtype: .generic, slice: []))])
+
+ Self.run(tests / "generic",
+ canonical: "0F0000000578000200000000FFFF00",
+ expected: ["x": .binary(.init(subtype: .generic,
+ slice: Base16.decode("ffff")))])
+
+ Self.run(tests / "function",
+ canonical: "0F0000000578000200000001FFFF00",
+ expected: ["x": .binary(.init(subtype: .function,
+ slice: Base16.decode("ffff")))])
+
+ Self.run(tests / "uuid",
+ canonical: "1D000000057800100000000473FFD26444B34C6990E8E7D1DFC035D400",
+ expected: ["x": .binary(.init(subtype: .uuid,
+ slice: Base16.decode("73ffd26444b34c6990e8e7d1dfc035d4")))])
+
+ Self.run(tests / "md5",
+ canonical: "1D000000057800100000000573FFD26444B34C6990E8E7D1DFC035D400",
+ expected: ["x": .binary(.init(subtype: .md5,
+ slice: Base16.decode("73ffd26444b34c6990e8e7d1dfc035d4")))])
+
+ Self.run(tests / "compressed",
+ canonical: "1D000000057800100000000773FFD26444B34C6990E8E7D1DFC035D400",
+ expected: ["x": .binary(.init(subtype: .compressed,
+ slice: Base16.decode("73ffd26444b34c6990e8e7d1dfc035d4")))])
+
+ Self.run(tests / "custom",
+ canonical: "0F0000000578000200000080FFFF00",
+ expected: ["x": .binary(.init(subtype: .custom(code: 0x80),
+ slice: Base16.decode("ffff")))])
+ // TODO: tests for legacy binary subtype 0x02
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/document.json
+ if let tests:TestGroup = tests / "document"
+ {
+ Self.run(tests / "empty",
+ canonical: "0D000000037800050000000000",
+ expected: ["x": [:]])
+
+ Self.run(tests / "empty-key",
+ canonical: "150000000378000D00000002000200000062000000",
+ expected: ["x": ["": "b"]])
+
+ Self.run(tests / "single-character-key",
+ canonical: "160000000378000E0000000261000200000062000000",
+ expected: ["x": ["a": "b"]])
+
+ Self.run(tests / "dollar-prefixed-key",
+ canonical: "170000000378000F000000022461000200000062000000",
+ expected: ["x": ["$a": "b"]])
+
+ Self.run(tests / "dollar-key",
+ canonical: "160000000378000E0000000224000200000061000000",
+ expected: ["x": ["$": "a"]])
+
+ Self.run(tests / "dotted-key",
+ canonical: "180000000378001000000002612E62000200000063000000",
+ expected: ["x": ["a.b": "c"]])
+
+ Self.run(tests / "dot-key",
+ canonical: "160000000378000E000000022E000200000061000000",
+ expected: ["x": [".": "a"]])
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/array.json
+ if let tests:TestGroup = tests / "tuple"
+ {
+ Self.run(tests / "empty",
+ canonical: "0D000000046100050000000000",
+ expected: ["a": []])
+ Self.run(tests / "single-element",
+ canonical: "140000000461000C0000001030000A0000000000",
+ expected: ["a": [.int32(10)]])
+
+ Self.run(tests / "single-element-empty-key",
+ degenerate: "130000000461000B00000010000A0000000000",
+ canonical: "140000000461000C0000001030000A0000000000",
+ expected: ["a": [.int32(10)]])
+
+ Self.run(tests / "single-element-invalid-key",
+ degenerate: "150000000461000D000000106162000A0000000000",
+ canonical: "140000000461000C0000001030000A0000000000",
+ expected: ["a": [.int32(10)]])
+
+ Self.run(tests / "multiple-element-duplicate-keys",
+ degenerate: "1b000000046100130000001030000a000000103000140000000000",
+ canonical: "1b000000046100130000001030000a000000103100140000000000",
+ expected: ["a": [.int32(10), .int32(20)]])
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/regex.json
+ if let tests:TestGroup = tests / "regex"
+ {
+ Self.run(tests / "empty",
+ canonical: "0A0000000B6100000000",
+ expected: ["a": .regex(.init(pattern: "", options: []))])
+
+ Self.run(tests / "empty-options",
+ canonical: "0D0000000B6100616263000000",
+ expected: ["a": .regex(.init(pattern: "abc", options: []))])
+
+ Self.run(tests / "I-HAVE-OPTIONS",
+ canonical: "0F0000000B610061626300696D0000",
+ expected: ["a": .regex(.init(pattern: "abc", options: [.i, .m]))])
+
+ Self.run(tests / "slash",
+ canonical: "110000000B610061622F636400696D0000",
+ expected: ["a": .regex(.init(pattern: "ab/cd", options: [.i, .m]))])
+
+ Self.run(tests / "non-alphabetized",
+ degenerate: "100000000B6100616263006D69780000",
+ canonical: "100000000B610061626300696D780000",
+ expected: ["a": .regex(.init(pattern: "abc", options: [.i, .m, .x]))])
+
+ Self.run(tests / "escaped",
+ canonical: "100000000B610061625C226162000000",
+ expected: ["a": .regex(.init(pattern: #"ab\"ab"#, options: []))])
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/string.json
+ if let tests:TestGroup = tests / "string"
+ {
+ Self.run(tests / "empty",
+ canonical: "0D000000026100010000000000",
+ expected: ["a": ""])
+
+ Self.run(tests / "single-character",
+ canonical: "0E00000002610002000000620000",
+ expected: ["a": "b"])
+
+ Self.run(tests / "multiple-character",
+ canonical: "190000000261000D0000006162616261626162616261620000",
+ expected: ["a": "abababababab"])
+
+ Self.run(tests / "utf-8-double-code-unit",
+ canonical: "190000000261000D000000C3A9C3A9C3A9C3A9C3A9C3A90000",
+ expected: ["a": "\u{e9}\u{e9}\u{e9}\u{e9}\u{e9}\u{e9}"])
+
+ Self.run(tests / "utf-8-triple-code-unit",
+ canonical: "190000000261000D000000E29886E29886E29886E298860000",
+ expected: ["a": "\u{2606}\u{2606}\u{2606}\u{2606}"])
+
+ Self.run(tests / "utf-8-null-bytes",
+ canonical: "190000000261000D0000006162006261620062616261620000",
+ expected: ["a": "ab\u{00}bab\u{00}babab"])
+
+ Self.run(tests / "escaped",
+ canonical:
+ """
+ 3200000002610026000000\
+ 61625C220102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F6162\
+ 0000
+ """,
+ expected:
+ [
+ "a":
+ """
+ ab\\\"\u{01}\u{02}\u{03}\u{04}\u{05}\u{06}\u{07}\u{08}\
+ \t\n\u{0b}\u{0c}\r\u{0e}\u{0f}\u{10}\
+ \u{11}\u{12}\u{13}\u{14}\u{15}\u{16}\u{17}\u{18}\u{19}\
+ \u{1a}\u{1b}\u{1c}\u{1d}\u{1e}\u{1f}ab
+ """
+ ])
+
+ Self.run(tests / "invalid-utf-8",
+ canonical: "0E00000002610002000000E90000",
+ expected: ["a": .string(.init(slice: [0xe9]))])
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/symbol.json
+ if let tests:TestGroup = tests / "symbol"
+ {
+ Self.run(tests / "empty",
+ degenerate: "0D0000000E6100010000000000",
+ canonical: "0D000000026100010000000000",
+ expected: ["a": ""])
+
+ Self.run(tests / "single-character",
+ degenerate: "0E0000000E610002000000620000",
+ canonical: "0E00000002610002000000620000",
+ expected: ["a": "b"])
+
+ Self.run(tests / "multiple-character",
+ degenerate: "190000000E61000D0000006162616261626162616261620000",
+ canonical: "190000000261000D0000006162616261626162616261620000",
+ expected: ["a": "abababababab"])
+
+ Self.run(tests / "utf-8-double-code-unit",
+ degenerate: "190000000E61000D000000C3A9C3A9C3A9C3A9C3A9C3A90000",
+ canonical: "190000000261000D000000C3A9C3A9C3A9C3A9C3A9C3A90000",
+ expected: ["a": "\u{e9}\u{e9}\u{e9}\u{e9}\u{e9}\u{e9}"])
+
+ Self.run(tests / "utf-8-triple-code-unit",
+ degenerate: "190000000E61000D000000E29886E29886E29886E298860000",
+ canonical: "190000000261000D000000E29886E29886E29886E298860000",
+ expected: ["a": "\u{2606}\u{2606}\u{2606}\u{2606}"])
+
+ Self.run(tests / "utf-8-null-bytes",
+ degenerate: "190000000E61000D0000006162006261620062616261620000",
+ canonical: "190000000261000D0000006162006261620062616261620000",
+ expected: ["a": "ab\u{00}bab\u{00}babab"])
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/code.json
+ if let tests:TestGroup = tests / "javascript"
+ {
+ Self.run(tests / "empty",
+ canonical: "0D0000000D6100010000000000",
+ expected: ["a": .javascript(.init(from: ""))])
+
+ Self.run(tests / "single-character",
+ canonical: "0E0000000D610002000000620000",
+ expected: ["a": .javascript(.init(from: "b"))])
+
+ Self.run(tests / "multiple-character",
+ canonical: "190000000D61000D0000006162616261626162616261620000",
+ expected: ["a": .javascript(.init(from: "abababababab"))])
+
+ Self.run(tests / "utf-8-double-code-unit",
+ canonical: "190000000D61000D000000C3A9C3A9C3A9C3A9C3A9C3A90000",
+ expected: ["a": .javascript(.init(from: "\u{e9}\u{e9}\u{e9}\u{e9}\u{e9}\u{e9}"))])
+
+ Self.run(tests / "utf-8-triple-code-unit",
+ canonical: "190000000D61000D000000E29886E29886E29886E298860000",
+ expected: ["a": .javascript(.init(from: "\u{2606}\u{2606}\u{2606}\u{2606}"))])
+
+ Self.run(tests / "utf-8-null-bytes",
+ canonical: "190000000D61000D0000006162006261620062616261620000",
+ expected: ["a": .javascript(.init(from: "ab\u{00}bab\u{00}babab"))])
+ }
+
+ // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/code_w_scope.json
+ if let tests:TestGroup = tests / "javascript-scope"
+ {
+ Self.run(tests / "empty",
+ canonical: "160000000F61000E0000000100000000050000000000",
+ expected: ["a": .javascriptScope([:], .init(from: ""))])
+
+ Self.run(tests / "empty-scope",
+ canonical: "1A0000000F610012000000050000006162636400050000000000",
+ expected: ["a": .javascriptScope([:], .init(from: "abcd"))])
+
+ Self.run(tests / "empty-code",
+ canonical: "1D0000000F61001500000001000000000C000000107800010000000000",
+ expected: ["a": .javascriptScope(["x": .int32(1)], .init(from: ""))])
+
+ Self.run(tests / "non-empty",
+ canonical: "210000000F6100190000000500000061626364000C000000107800010000000000",
+ expected: ["a": .javascriptScope(["x": .int32(1)], .init(from: "abcd"))])
+
+ Self.run(tests / "unicode",
+ canonical: "1A0000000F61001200000005000000C3A9006400050000000000",
+ expected: ["a": .javascriptScope([:], .init(from: "\u{e9}\u{00}d"))])
+ }
+ }
+}
+extension Main.ValidBSON
+{
+ private static
+ func run(_ tests:TestGroup?,
+ degenerate:String? = nil,
+ canonical:String,
+ expected:BSON.DocumentView<[UInt8]>)
+ {
+ guard let tests:TestGroup
+ else
+ {
+ return
+ }
+
+ let canonical:[UInt8] = Base16.decode(canonical.utf8)
+ let size:Int32 = canonical.prefix(4).withUnsafeBytes
+ {
+ .init(littleEndian: $0.load(as: Int32.self))
+ }
+
+ let document:BSON.DocumentView> = .init(
+ slicing: canonical.dropFirst(4).dropLast())
+
+ tests.expect(canonical.count ==? .init(size))
+ tests.expect(document.header ==? size)
+
+ tests.expect(true: expected ~~ document)
+ tests.expect(true: expected == document)
+
+ if let degenerate:String
+ {
+ let degenerate:[UInt8] = Base16.decode(degenerate.utf8)
+ let document:BSON.DocumentView> = .init(
+ slicing: degenerate.dropFirst(4).dropLast())
+
+ (tests / "canonicalization")?.do
+ {
+ let canonicalized:BSON.DocumentView> =
+ try document.canonicalized()
+
+ tests.expect(true: expected ~~ document)
+ tests.expect(true: expected == canonicalized)
+ }
+ }
+ }
+}
diff --git a/Sources/BSONTests/Main.swift b/Sources/BSONTests/Main.swift
index f7c08a45..3b8d7cfb 100644
--- a/Sources/BSONTests/Main.swift
+++ b/Sources/BSONTests/Main.swift
@@ -1,789 +1,8 @@
-import Base16
-import BSON
-import BSONReflection
import Testing
@main
-enum Main:SyncTests
+enum Main:TestMain
{
static
- func run(tests:Tests)
- {
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/multi-type.json
- // cannot use this test, because it encodes a deprecated binary subtype, which is
- // (intentionally) impossible to construct with swift-bson.
-
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/maxkey.json
- do
- {
- TestValidBSON(tests / "max",
- canonical: "080000007F610000",
- expected: ["a": .max])
- }
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/minkey.json
- do
- {
- TestValidBSON(tests / "min",
- canonical: "08000000FF610000",
- expected: ["a": .min])
- }
-
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/null.json
- do
- {
- TestValidBSON(tests / "null",
- canonical: "080000000A610000",
- expected: ["a": .null])
- }
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/undefined.json
- do
- {
- TestValidBSON(tests / "undefined",
- degenerate: "0800000006610000",
- canonical: "080000000A610000",
- expected: ["a": .null])
- }
-
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/boolean.json
- if let tests:TestGroup = tests / "bool"
- {
-
- TestValidBSON(tests / "true",
- canonical: "090000000862000100",
- expected: ["b": true])
- TestValidBSON(tests / "false",
- canonical: "090000000862000000",
- expected: ["b": false])
-
- TestInvalidBSON(tests / "invalid-subtype",
- invalid: "090000000862000200",
- catching: BSON.BooleanSubtypeError.init(invalid: 2))
-
- TestInvalidBSON(tests / "invalid-subtype-negative",
- invalid: "09000000086200FF00",
- catching: BSON.BooleanSubtypeError.init(invalid: 255))
- }
-
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/int32.json
- if let tests:TestGroup = tests / "int32"
- {
-
- TestValidBSON(tests / "min",
- canonical: "0C0000001069000000008000",
- expected: ["i": .int32(-2147483648)])
-
- TestValidBSON(tests / "max",
- canonical: "0C000000106900FFFFFF7F00",
- expected: ["i": .int32(2147483647)])
-
- TestValidBSON(tests / "-1",
- canonical: "0C000000106900FFFFFFFF00",
- expected: ["i": .int32(-1)])
-
- TestValidBSON(tests / "0",
- canonical: "0C0000001069000000000000",
- expected: ["i": .int32(0)])
-
- TestValidBSON(tests / "+1",
- canonical: "0C0000001069000100000000",
- expected: ["i": .int32(1)])
-
- TestInvalidBSON(tests / "truncated",
- invalid: "09000000_10_6100_05_00",
- catching: BSON.InputError.init(expected: .bytes(4), encountered: 1))
- }
-
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/int32.json
- if let tests:TestGroup = tests / "int64"
- {
-
- TestValidBSON(tests / "min",
- canonical: "10000000126100000000000000008000",
- expected: ["a": .int64(-9223372036854775808)])
-
- TestValidBSON(tests / "max",
- canonical: "10000000126100FFFFFFFFFFFFFF7F00",
- expected: ["a": .int64(9223372036854775807)])
-
- TestValidBSON(tests / "-1",
- canonical: "10000000126100FFFFFFFFFFFFFFFF00",
- expected: ["a": .int64(-1)])
-
- TestValidBSON(tests / "0",
- canonical: "10000000126100000000000000000000",
- expected: ["a": .int64(0)])
-
- TestValidBSON(tests / "+1",
- canonical: "10000000126100010000000000000000",
- expected: ["a": .int64(1)])
-
- TestInvalidBSON(tests / "truncated",
- invalid: "0C000000_12_6100_12345678_00",
- catching: BSON.InputError.init(expected: .bytes(8), encountered: 4))
- }
-
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/timestamp.json
- if let tests:TestGroup = tests / "uint64"
- {
-
- TestValidBSON(tests / "(123456789, 42)",
- canonical: "100000001161002A00000015CD5B0700",
- expected: ["a": .uint64(123456789 << 32 | 42)])
-
- TestValidBSON(tests / "ones",
- canonical: "10000000116100FFFFFFFFFFFFFFFF00",
- expected: ["a": .uint64(.max)])
-
- TestValidBSON(tests / "(4000000000, 4000000000)",
- canonical: "1000000011610000286BEE00286BEE00",
- expected: ["a": .uint64(4000000000 << 32 | 4000000000)])
-
- TestInvalidBSON(tests / "truncated",
- invalid: "0F000000_11_6100_2A00000015CD5B_00",
- catching: BSON.InputError.init(expected: .bytes(8), encountered: 7))
- }
-
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/top.json
- if let tests:TestGroup = tests / "top"
- {
-
- TestValidBSON(tests / "dollar-prefixed-key",
- canonical: "0F00000010246B6579002A00000000",
- expected: ["$key": .int32(42)])
-
- TestValidBSON(tests / "dollar-key",
- canonical: "0E00000002240002000000610000",
- expected: ["$": "a"])
-
- TestValidBSON(tests / "dotted-key",
- canonical: "1000000002612E620002000000630000",
- expected: ["a.b": "c"])
-
- TestValidBSON(tests / "dot-key",
- canonical: "0E000000022E0002000000610000",
- expected: [".": "a"])
-
- TestValidBSON(tests / "empty-truncated-header",
- degenerate: "0100000000",
- canonical: "0500000000",
- expected: [:])
-
- TestValidBSON(tests / "empty",
- canonical: "0500000000",
- expected: [:])
-
- TestValidBSON(tests / "invalid-end-of-object-0x01",
- degenerate: "05000000_01",
- canonical: "05000000_00",
- expected: [:])
-
- TestValidBSON(tests / "invalid-end-of-object-0xff",
- degenerate: "05000000_FF",
- canonical: "05000000_00",
- expected: [:])
-
- TestValidBSON(tests / "invalid-end-of-object-0x70",
- degenerate: "05000000_70",
- canonical: "05000000_00",
- expected: [:])
-
- TestInvalidBSON(tests / "zeroes",
- invalid: "00000000_000000000000",
- // ^~~~~~~~
- catching: BSON.HeaderError.init(length: 0))
-
- TestInvalidBSON(tests / "invalid-length-over",
- invalid: "12000000_02_666F6F00_04000000_626172",
- // ^~~~~~~~
- catching: BSON.InputError.init(expected: .bytes(0x12 - 4), encountered: 12))
-
- TestInvalidBSON(tests / "invalid-length-under",
- invalid: "12000000_02_666F6F00_04000000_62617200_00_DEADBEEF",
- // ^~~~~~~~
- catching: BSON.InputError.init(expected: .end, encountered: 4))
-
- TestInvalidBSON(tests / "invalid-type-0x00",
- invalid: "07000000_00_0000",
- // ^~
- catching: BSON.TypeError.init(invalid: 0x00))
-
- TestInvalidBSON(tests / "invalid-type-0x80",
- invalid: "07000000_80_0000",
- // ^~
- catching: BSON.TypeError.init(invalid: 0x80))
-
- TestInvalidBSON(tests / "truncated",
- invalid: "12000000_02_666F",
- catching: BSON.InputError.init(expected: .bytes(0x12 - 4), encountered: 3))
-
- TestInvalidBSON(tests / "invalid-key",
- invalid: "0D000000_10_7800_00_0100000000",
- // ^~
- catching: BSON.TypeError.init(invalid: 0x00))
- }
-
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/decimal128-1.json
- if let tests:TestGroup = tests / "decimal128"
- {
-
- TestValidBSON(tests / "positive-quiet-nan",
- canonical: "180000001364000000000000000000000000000000007C00",
- expected: ["d": .decimal128(.init(
- high: 0x7C00_0000_0000_0000,
- low: 0x0000_0000_0000_0000))])
-
- TestValidBSON(tests / "negative-quiet-nan",
- canonical: "18000000136400000000000000000000000000000000FC00",
- expected: ["d": .decimal128(.init(
- high: 0xFC00_0000_0000_0000,
- low: 0x0000_0000_0000_0000))])
-
- TestValidBSON(tests / "positive-signaling-nan",
- canonical: "180000001364000000000000000000000000000000007E00",
- expected: ["d": .decimal128(.init(
- high: 0x7E00_0000_0000_0000,
- low: 0x0000_0000_0000_0000))])
-
- TestValidBSON(tests / "negative-signaling-nan",
- canonical: "18000000136400000000000000000000000000000000FE00",
- expected: ["d": .decimal128(.init(
- high: 0xFE00_0000_0000_0000,
- low: 0x0000_0000_0000_0000))])
-
- // this only serves to verify we are handling byte-order correctly;
- // there is very little point in elaborating decimal128 tests further
- TestValidBSON(tests / "largest",
- canonical: "18000000136400F2AF967ED05C82DE3297FF6FDE3C403000",
- expected: ["d": .decimal128(.init(
- high: 0x3040_3CDE_6FFF_9732,
- low: 0xDE82_5CD0_7E96_AFF2))])
- }
-
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/datetime.json
- if let tests:TestGroup = tests / "millisecond"
- {
-
- TestValidBSON(tests / "epoch",
- canonical: "10000000096100000000000000000000",
- expected: ["a": .millisecond(0)])
-
- TestValidBSON(tests / "positive",
- canonical: "10000000096100C5D8D6CC3B01000000",
- expected: ["a": .millisecond(1356351330501)])
-
- TestValidBSON(tests / "negative",
- canonical: "10000000096100C33CE7B9BDFFFFFF00",
- expected: ["a": .millisecond(-284643869501)])
-
- TestValidBSON(tests / "positive-2",
- canonical: "1000000009610000DC1FD277E6000000",
- expected: ["a": .millisecond(253402300800000)])
-
- TestValidBSON(tests / "positive-3",
- canonical: "10000000096100D1D6D6CC3B01000000",
- expected: ["a": .millisecond(1356351330001)])
-
- TestInvalidBSON(tests / "truncated",
- invalid: "0C000000_0961001234567800",
- catching: BSON.InputError.init(expected: .bytes(8), encountered: 4))
- }
-
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/double.json
- if let tests:TestGroup = tests / "double"
- {
-
- TestValidBSON(tests / "+1.0",
- canonical: "10000000016400000000000000F03F00",
- expected: ["d": .double(1.0)])
-
- TestValidBSON(tests / "-1.0",
- canonical: "10000000016400000000000000F0BF00",
- expected: ["d": .double(-1.0)])
-
- TestValidBSON(tests / "+1.0001220703125",
- canonical: "10000000016400000000008000F03F00",
- expected: ["d": .double(1.0001220703125)])
-
- TestValidBSON(tests / "-1.0001220703125",
- canonical: "10000000016400000000008000F0BF00",
- expected: ["d": .double(-1.0001220703125)])
-
- TestValidBSON(tests / "1.2345678921232E+18",
- canonical: "100000000164002a1bf5f41022b14300",
- expected: ["d": .double(1.2345678921232e18)])
-
- TestValidBSON(tests / "-1.2345678921232E+18",
- canonical: "100000000164002a1bf5f41022b1c300",
- expected: ["d": .double(-1.2345678921232e18)])
-
- // remaining corpus test cases are pointless because swift cannot distinguish
- // between -0.0 and +0.0
-
- // note: frameshift
- TestInvalidBSON(tests / "truncated",
- invalid: "0B000000_0164000000F03F00",
- // ^~~~~~~~
- catching: BSON.InputError.init(expected: .end, encountered: 1))
- }
-
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/oid.json
- if let tests:TestGroup = tests / "id"
- {
-
- let id:BSON.Identifier = 0x0123_4567_89AB_CDEF_4567_3210
-
- tests.expect(id.timestamp ==? 0x0123_4567)
- tests.expect(true: id.seed == (0x89, 0xAB, 0xCD, 0xEF, 0x45))
- tests.expect(true: id.ordinal == (0x67, 0x32, 0x10))
-
- tests.expect(id ==? .init(timestamp: id.timestamp, seed: id.seed, ordinal: id.ordinal))
-
- TestValidBSON(tests / "zeroes",
- canonical: "1400000007610000000000000000000000000000",
- expected: ["a": .id(0x00000000_00000000_00_000000)])
-
- TestValidBSON(tests / "ones",
- canonical: "14000000076100FFFFFFFFFFFFFFFFFFFFFFFF00",
- expected: ["a": .id(0xffffffff_ffffffff_ff_ffffff)])
-
- TestValidBSON(tests / "random",
- canonical: "1400000007610056E1FC72E0C917E9C471416100",
- expected: ["a": .id(0x56e1fc72_e0c917e9_c4_714161)])
-
- TestInvalidBSON(tests / "truncated",
- invalid: "12000000_07_6100_56E1FC72E0C917E9C471",
- // ^~~~~~~~
- catching: BSON.InputError.init(expected: .bytes(0x12 - 4), encountered: 13))
- }
-
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/dbpointer.json
- if let tests:TestGroup = tests / "pointer"
- {
-
- TestValidBSON(tests / "ascii",
- canonical: "1A0000000C610002000000620056E1FC72E0C917E9C471416100",
- expected: ["a": .pointer(.init(from: "b"), .init(
- 0x56e1fc72, 0xe0c917e9, 0xc4_714161))])
-
- TestValidBSON(tests / "unicode",
- canonical: "1B0000000C610003000000C3A90056E1FC72E0C917E9C471416100",
- expected: ["a": .pointer(.init(from: "é"), .init(
- 0x56e1fc72, 0xe0c917e9, 0xc4_714161))])
-
- TestInvalidBSON(tests / "invalid-length-negative",
- invalid: "1A000000_0C_6100_FFFFFFFF_620056E1FC72E0C917E9C471416100",
- // ^~~~~~~~
- catching: BSON.HeaderError.init(length: -1))
-
- TestInvalidBSON(tests / "invalid-length-zero",
- invalid: "1A000000_0C_6100_00000000_620056E1FC72E0C917E9C471416100",
- // ^~~~~~~~
- catching: BSON.HeaderError.init(length: 0))
-
- TestInvalidBSON(tests / "truncated",
- invalid: "16000000_0C_6100_03000000_616200_56E1FC72E0C91700",
- catching: BSON.InputError.init(expected: .bytes(12), encountered: 7))
-
- TestInvalidBSON(tests / "truncated-identifier",
- invalid: "1A000000_0C_6100_03000000_616200_56E1FC72E0C917E9C4716100",
- catching: BSON.InputError.init(expected: .bytes(12), encountered: 11))
- }
-
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/binary.json
- if let tests:TestGroup = tests / "binary"
- {
-
- TestValidBSON(tests / "generic-empty",
- canonical: "0D000000057800000000000000",
- expected: ["x": .binary(.init(subtype: .generic, slice: []))])
-
- TestValidBSON(tests / "generic",
- canonical: "0F0000000578000200000000FFFF00",
- expected: ["x": .binary(.init(subtype: .generic,
- slice: Base16.decode("ffff")))])
-
- TestValidBSON(tests / "function",
- canonical: "0F0000000578000200000001FFFF00",
- expected: ["x": .binary(.init(subtype: .function,
- slice: Base16.decode("ffff")))])
-
- TestValidBSON(tests / "uuid",
- canonical: "1D000000057800100000000473FFD26444B34C6990E8E7D1DFC035D400",
- expected: ["x": .binary(.init(subtype: .uuid,
- slice: Base16.decode("73ffd26444b34c6990e8e7d1dfc035d4")))])
-
- TestValidBSON(tests / "md5",
- canonical: "1D000000057800100000000573FFD26444B34C6990E8E7D1DFC035D400",
- expected: ["x": .binary(.init(subtype: .md5,
- slice: Base16.decode("73ffd26444b34c6990e8e7d1dfc035d4")))])
-
- TestValidBSON(tests / "compressed",
- canonical: "1D000000057800100000000773FFD26444B34C6990E8E7D1DFC035D400",
- expected: ["x": .binary(.init(subtype: .compressed,
- slice: Base16.decode("73ffd26444b34c6990e8e7d1dfc035d4")))])
-
- TestValidBSON(tests / "custom",
- canonical: "0F0000000578000200000080FFFF00",
- expected: ["x": .binary(.init(subtype: .custom(code: 0x80),
- slice: Base16.decode("ffff")))])
-
- TestInvalidBSON(tests / "invalid-length-over",
- invalid: "1D000000_05_7800_FF000000_05_73FFD26444B34C6990E8E7D1DFC035D400",
- // ^~~~~~~~
- catching: BSON.InputError.init(expected: .bytes(0xFF + 1), encountered: 17))
-
- TestInvalidBSON(tests / "invalid-length-negative",
- invalid: "0D000000057800FFFFFFFF0000",
- catching: BSON.BinaryViewError.init(expected: .subtype))
- // TODO: tests for legacy binary subtype 0x02
- }
-
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/document.json
- if let tests:TestGroup = tests / "document"
- {
-
- TestValidBSON(tests / "empty",
- canonical: "0D000000037800050000000000",
- expected: ["x": [:]])
-
- TestValidBSON(tests / "empty-key",
- canonical: "150000000378000D00000002000200000062000000",
- expected: ["x": ["": "b"]])
-
- TestValidBSON(tests / "single-character-key",
- canonical: "160000000378000E0000000261000200000062000000",
- expected: ["x": ["a": "b"]])
-
- TestValidBSON(tests / "dollar-prefixed-key",
- canonical: "170000000378000F000000022461000200000062000000",
- expected: ["x": ["$a": "b"]])
-
- TestValidBSON(tests / "dollar-key",
- canonical: "160000000378000E0000000224000200000061000000",
- expected: ["x": ["$": "a"]])
-
- TestValidBSON(tests / "dotted-key",
- canonical: "180000000378001000000002612E62000200000063000000",
- expected: ["x": ["a.b": "c"]])
-
- TestValidBSON(tests / "dot-key",
- canonical: "160000000378000E000000022E000200000061000000",
- expected: ["x": [".": "a"]])
-
- TestInvalidBSON(tests / "invalid-length-over",
- invalid: "18000000_03_666F6F00_0F000000_10_62617200_FFFFFF7F_0000",
- // ^~~~~~~~
- catching: BSON.InputError.init(expected: .bytes(0x0F - 4), encountered: 10))
-
- TestInvalidBSON(tests / "invalid-length-under",
- invalid: "15000000_03_666F6F00_0A000000_08_62617200_01_00_00",
- // ^~
- catching: BSON.InputError.init(expected: .bytes(1)))
-
- TestInvalidBSON(tests / "invalid-value",
- invalid: "1C000000_03_666F6F00_12000000_02_62617200_05000000_62617A000000",
- // ^~~~~~~~
- catching: BSON.InputError.init(expected: .bytes(5), encountered: 4))
-
- TestInvalidBSON(tests / "invalid-key",
- invalid: "15000000_03_7800_0D000000_10_6100_00010000_00_0000",
- // ^~
- catching: BSON.TypeError.init(invalid: 0))
- }
-
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/array.json
- if let tests:TestGroup = tests / "tuple"
- {
-
- TestValidBSON(tests / "empty",
- canonical: "0D000000046100050000000000",
- expected: ["a": []])
- TestValidBSON(tests / "single-element",
- canonical: "140000000461000C0000001030000A0000000000",
- expected: ["a": [.int32(10)]])
-
- TestValidBSON(tests / "single-element-empty-key",
- degenerate: "130000000461000B00000010000A0000000000",
- canonical: "140000000461000C0000001030000A0000000000",
- expected: ["a": [.int32(10)]])
-
- TestValidBSON(tests / "single-element-invalid-key",
- degenerate: "150000000461000D000000106162000A0000000000",
- canonical: "140000000461000C0000001030000A0000000000",
- expected: ["a": [.int32(10)]])
-
- TestValidBSON(tests / "multiple-element-duplicate-keys",
- degenerate: "1b000000046100130000001030000a000000103000140000000000",
- canonical: "1b000000046100130000001030000a000000103100140000000000",
- expected: ["a": [.int32(10), .int32(20)]])
-
- TestInvalidBSON(tests / "invalid-length-over",
- invalid: "14000000_04_6100_0D000000_10_30000A00_00_000000",
- // ^~~~~~~~
- catching: BSON.InputError.init(expected: .bytes(0x0D - 4), encountered: 8))
-
- TestInvalidBSON(tests / "invalid-length-under",
- invalid: "14000000_04_6100_0B000000_10_30000A00_00_000000",
- // ^~~~~~~~
- catching: BSON.InputError.init(expected: .bytes(4), encountered: 3))
-
- TestInvalidBSON(tests / "invalid-element",
- invalid: "1A000000_04_666F6F00_100000000230000500000062617A000000",
- //
- catching: BSON.InputError.init(expected: .bytes(5), encountered: 4))
- }
-
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/regex.json
- if let tests:TestGroup = tests / "regex"
- {
-
- TestValidBSON(tests / "empty",
- canonical: "0A0000000B6100000000",
- expected: ["a": .regex(.init(pattern: "", options: []))])
-
- TestValidBSON(tests / "empty-options",
- canonical: "0D0000000B6100616263000000",
- expected: ["a": .regex(.init(pattern: "abc", options: []))])
-
- TestValidBSON(tests / "I-HAVE-OPTIONS",
- canonical: "0F0000000B610061626300696D0000",
- expected: ["a": .regex(.init(pattern: "abc", options: [.i, .m]))])
-
- TestValidBSON(tests / "slash",
- canonical: "110000000B610061622F636400696D0000",
- expected: ["a": .regex(.init(pattern: "ab/cd", options: [.i, .m]))])
-
- TestValidBSON(tests / "non-alphabetized",
- degenerate: "100000000B6100616263006D69780000",
- canonical: "100000000B610061626300696D780000",
- expected: ["a": .regex(.init(pattern: "abc", options: [.i, .m, .x]))])
-
- TestValidBSON(tests / "escaped",
- canonical: "100000000B610061625C226162000000",
- expected: ["a": .regex(.init(pattern: #"ab\"ab"#, options: []))])
-
- // note: frameshift
- TestInvalidBSON(tests / "invalid-pattern",
- invalid: "0F0000000B610061006300696D0000",
- catching: BSON.Regex.OptionError.init(invalid: "c"))
- // note: frameshift
- TestInvalidBSON(tests / "invalid-options",
- invalid: "100000000B61006162630069006D0000",
- catching: BSON.TypeError.init(invalid: 109))
- }
-
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/string.json
- if let tests:TestGroup = tests / "string"
- {
-
- TestValidBSON(tests / "empty",
- canonical: "0D000000026100010000000000",
- expected: ["a": ""])
-
- TestValidBSON(tests / "single-character",
- canonical: "0E00000002610002000000620000",
- expected: ["a": "b"])
-
- TestValidBSON(tests / "multiple-character",
- canonical: "190000000261000D0000006162616261626162616261620000",
- expected: ["a": "abababababab"])
-
- TestValidBSON(tests / "utf-8-double-code-unit",
- canonical: "190000000261000D000000C3A9C3A9C3A9C3A9C3A9C3A90000",
- expected: ["a": "\u{e9}\u{e9}\u{e9}\u{e9}\u{e9}\u{e9}"])
-
- TestValidBSON(tests / "utf-8-triple-code-unit",
- canonical: "190000000261000D000000E29886E29886E29886E298860000",
- expected: ["a": "\u{2606}\u{2606}\u{2606}\u{2606}"])
-
- TestValidBSON(tests / "utf-8-null-bytes",
- canonical: "190000000261000D0000006162006261620062616261620000",
- expected: ["a": "ab\u{00}bab\u{00}babab"])
-
- TestValidBSON(tests / "escaped",
- canonical:
- """
- 3200000002610026000000\
- 61625C220102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F6162\
- 0000
- """,
- expected:
- [
- "a":
- """
- ab\\\"\u{01}\u{02}\u{03}\u{04}\u{05}\u{06}\u{07}\u{08}\
- \t\n\u{0b}\u{0c}\r\u{0e}\u{0f}\u{10}\
- \u{11}\u{12}\u{13}\u{14}\u{15}\u{16}\u{17}\u{18}\u{19}\
- \u{1a}\u{1b}\u{1c}\u{1d}\u{1e}\u{1f}ab
- """
- ])
-
- TestInvalidBSON(tests / "missing-trailing-null-byte",
- invalid: "0C000000_02_6100_00000000_00",
- // ^~~~~~~~
- catching: BSON.HeaderError.init(length: 0))
-
- TestInvalidBSON(tests / "invalid-length-negative",
- invalid: "0C000000_02_6100_FFFFFFFF_00",
- // ^~~~~~~~
- catching: BSON.HeaderError.init(length: -1))
-
- TestInvalidBSON(tests / "invalid-length-over",
- invalid: "10000000_02_6100_05000000_62006200_00",
- // ^~~~~~~~
- catching: BSON.InputError.init(expected: .bytes(5), encountered: 4))
-
- TestInvalidBSON(tests / "invalid-length-over-document",
- invalid: "12000000_02_00_FFFFFF00_666F6F6261720000",
- // ^~~~~~~~
- catching: BSON.InputError.init(expected: .bytes(0xffffff), encountered: 7))
-
- TestInvalidBSON(tests / "invalid-length-under",
- invalid: "0E000000_02_6100_01000000_00_00_00",
- // ^~
- catching: BSON.TypeError.init(invalid: 0x00))
-
- TestValidBSON(tests / "invalid-utf-8",
- canonical: "0E00000002610002000000E90000",
- expected: ["a": .string(.init(slice: [0xe9]))])
- }
-
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/symbol.json
- if let tests:TestGroup = tests / "symbol"
- {
-
- TestValidBSON(tests / "empty",
- degenerate: "0D0000000E6100010000000000",
- canonical: "0D000000026100010000000000",
- expected: ["a": ""])
-
- TestValidBSON(tests / "single-character",
- degenerate: "0E0000000E610002000000620000",
- canonical: "0E00000002610002000000620000",
- expected: ["a": "b"])
-
- TestValidBSON(tests / "multiple-character",
- degenerate: "190000000E61000D0000006162616261626162616261620000",
- canonical: "190000000261000D0000006162616261626162616261620000",
- expected: ["a": "abababababab"])
-
- TestValidBSON(tests / "utf-8-double-code-unit",
- degenerate: "190000000E61000D000000C3A9C3A9C3A9C3A9C3A9C3A90000",
- canonical: "190000000261000D000000C3A9C3A9C3A9C3A9C3A9C3A90000",
- expected: ["a": "\u{e9}\u{e9}\u{e9}\u{e9}\u{e9}\u{e9}"])
-
- TestValidBSON(tests / "utf-8-triple-code-unit",
- degenerate: "190000000E61000D000000E29886E29886E29886E298860000",
- canonical: "190000000261000D000000E29886E29886E29886E298860000",
- expected: ["a": "\u{2606}\u{2606}\u{2606}\u{2606}"])
-
- TestValidBSON(tests / "utf-8-null-bytes",
- degenerate: "190000000E61000D0000006162006261620062616261620000",
- canonical: "190000000261000D0000006162006261620062616261620000",
- expected: ["a": "ab\u{00}bab\u{00}babab"])
- }
-
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/code.json
- if let tests:TestGroup = tests / "javascript"
- {
-
- TestValidBSON(tests / "empty",
- canonical: "0D0000000D6100010000000000",
- expected: ["a": .javascript(.init(from: ""))])
-
- TestValidBSON(tests / "single-character",
- canonical: "0E0000000D610002000000620000",
- expected: ["a": .javascript(.init(from: "b"))])
-
- TestValidBSON(tests / "multiple-character",
- canonical: "190000000D61000D0000006162616261626162616261620000",
- expected: ["a": .javascript(.init(from: "abababababab"))])
-
- TestValidBSON(tests / "utf-8-double-code-unit",
- canonical: "190000000D61000D000000C3A9C3A9C3A9C3A9C3A9C3A90000",
- expected: ["a": .javascript(.init(from: "\u{e9}\u{e9}\u{e9}\u{e9}\u{e9}\u{e9}"))])
-
- TestValidBSON(tests / "utf-8-triple-code-unit",
- canonical: "190000000D61000D000000E29886E29886E29886E298860000",
- expected: ["a": .javascript(.init(from: "\u{2606}\u{2606}\u{2606}\u{2606}"))])
-
- TestValidBSON(tests / "utf-8-null-bytes",
- canonical: "190000000D61000D0000006162006261620062616261620000",
- expected: ["a": .javascript(.init(from: "ab\u{00}bab\u{00}babab"))])
-
- TestInvalidBSON(tests / "missing-trailing-null-byte",
- invalid: "0C000000_0D_6100_00000000_00",
- // ^~~~~~~~
- catching: BSON.HeaderError.init(length: 0))
-
- TestInvalidBSON(tests / "invalid-length-negative",
- invalid: "0C0000000D6100FFFFFFFF00",
- catching: BSON.HeaderError.init(length: -1))
-
- TestInvalidBSON(tests / "invalid-length-over",
- invalid: "10000000_0D_6100_05000000_6200620000",
- // ^~~~~~~~
- catching: BSON.InputError.init(expected: .bytes(5), encountered: 4))
-
- TestInvalidBSON(tests / "invalid-length-over-document",
- invalid: "12000000_0D_00_FFFFFF00_666F6F6261720000",
- // ^~~~~~~~
- catching: BSON.InputError.init(expected: .bytes(0xffffff), encountered: 7))
-
- TestInvalidBSON(tests / "invalid-length-under",
- invalid: "0E000000_0D_6100_01000000_00_00_00",
- // ^~
- catching: BSON.TypeError.init(invalid: 0x00))
- }
-
- // https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/code_w_scope.json
- if let tests:TestGroup = tests / "javascript-scope"
- {
-
- TestValidBSON(tests / "empty",
- canonical: "160000000F61000E0000000100000000050000000000",
- expected: ["a": .javascriptScope([:], .init(from: ""))])
-
- TestValidBSON(tests / "empty-scope",
- canonical: "1A0000000F610012000000050000006162636400050000000000",
- expected: ["a": .javascriptScope([:], .init(from: "abcd"))])
-
- TestValidBSON(tests / "empty-code",
- canonical: "1D0000000F61001500000001000000000C000000107800010000000000",
- expected: ["a": .javascriptScope(["x": .int32(1)], .init(from: ""))])
-
- TestValidBSON(tests / "non-empty",
- canonical: "210000000F6100190000000500000061626364000C000000107800010000000000",
- expected: ["a": .javascriptScope(["x": .int32(1)], .init(from: "abcd"))])
-
- TestValidBSON(tests / "unicode",
- canonical: "1A0000000F61001200000005000000C3A9006400050000000000",
- expected: ["a": .javascriptScope([:], .init(from: "\u{e9}\u{00}d"))])
-
- // note: we do not validate the redundant field length,
- // so those tests are not included
-
- // note: the length is actually too short, but because we use the component-wise
- // length headers instead of the field length, this manifests itself as a
- // frameshift error.
- TestInvalidBSON(tests / "invalid-length-frameshift-clips-scope",
- invalid: "28000000_0F_6100_20000000_04000000_61626364_00130000_0010780001000000107900010000000000",
- // ^~~~~~~~
- catching: BSON.InputError.init(expected: .bytes(0x00_00_13_00 - 4), encountered: 16))
-
- TestInvalidBSON(tests / "invalid-length-over",
- invalid: "28000000_0F_6100_20000000_06000000_616263640013_00000010_780001000000107900010000000000",
- // ^~~~~~~~
- catching: BSON.InputError.init(expected: .bytes(0x10_00_00_00 - 4), encountered: 14))
- // note: frameshift
- TestInvalidBSON(tests / "invalid-length-frameshift",
- invalid: "28000000_0F_6100_20000000_FF000000_61626364001300000010780001000000107900010000000000",
- catching: BSON.InputError.init(expected: .bytes(255), encountered: 24))
-
- TestInvalidBSON(tests / "invalid-scope",
- invalid: "1C000000_0F_00_15000000_01000000_00_0C000000_02_00000000_00000000",
- // ^~~~~~~~
- catching: BSON.HeaderError.init(length: 0))
- }
- }
+ let all:[any TestBattery.Type] = [ValidBSON.self, InvalidBSON.self]
}
diff --git a/Sources/BSONTests/TestInvalidBSON.swift b/Sources/BSONTests/TestInvalidBSON.swift
deleted file mode 100644
index 04a0b746..00000000
--- a/Sources/BSONTests/TestInvalidBSON.swift
+++ /dev/null
@@ -1,25 +0,0 @@
-import Base16
-import BSON
-import BSONReflection
-import Testing
-
-func TestInvalidBSON(_ tests:TestGroup?, invalid:String, catching error:some Error & Equatable)
-{
- guard let tests:TestGroup
- else
- {
- return
- }
-
- let invalid:[UInt8] = Base16.decode(invalid.utf8)
-
- var input:BSON.Input<[UInt8]> = .init(invalid)
-
- tests.do(catching: error)
- {
- let document:BSON.DocumentView> = try input.parse(
- as: BSON.DocumentView>.self)
- try input.finish()
- _ = try document.canonicalized()
- }
-}
diff --git a/Sources/BSONTests/TestValidBSON.swift b/Sources/BSONTests/TestValidBSON.swift
deleted file mode 100644
index e3499226..00000000
--- a/Sources/BSONTests/TestValidBSON.swift
+++ /dev/null
@@ -1,47 +0,0 @@
-import Base16
-import BSON
-import BSONReflection
-import Testing
-
-func TestValidBSON(_ tests:TestGroup?,
- degenerate:String? = nil,
- canonical:String,
- expected:BSON.DocumentView<[UInt8]>)
-{
- guard let tests:TestGroup
- else
- {
- return
- }
-
- let canonical:[UInt8] = Base16.decode(canonical.utf8)
- let size:Int32 = canonical.prefix(4).withUnsafeBytes
- {
- .init(littleEndian: $0.load(as: Int32.self))
- }
-
- let document:BSON.DocumentView> = .init(
- slicing: canonical.dropFirst(4).dropLast())
-
- tests.expect(canonical.count ==? .init(size))
- tests.expect(document.header ==? size)
-
- tests.expect(true: expected ~~ document)
- tests.expect(true: expected == document)
-
- if let degenerate:String
- {
- let degenerate:[UInt8] = Base16.decode(degenerate.utf8)
- let document:BSON.DocumentView> = .init(
- slicing: degenerate.dropFirst(4).dropLast())
-
- (tests / "canonicalization")?.do
- {
- let canonicalized:BSON.DocumentView> =
- try document.canonicalized()
-
- tests.expect(true: expected ~~ document)
- tests.expect(true: expected == canonicalized)
- }
- }
-}
diff --git a/Sources/BSONTypes/BSON.DocumentView.swift b/Sources/BSONTypes/BSON.DocumentView.swift
deleted file mode 100644
index af59f772..00000000
--- a/Sources/BSONTypes/BSON.DocumentView.swift
+++ /dev/null
@@ -1,76 +0,0 @@
-import BSONTraversal
-
-extension BSON
-{
- /// A BSON document. The backing storage of this type is opaque,
- /// permitting lazy parsing of its inline content.
- @frozen public
- struct DocumentView where Bytes:RandomAccessCollection
- {
- /// The raw data backing this document. This collection *does not*
- /// include the trailing null byte that typically appears after its
- /// inline field list.
- public
- let slice:Bytes
-
- /// Stores the argument in ``slice`` unchanged.
- ///
- /// > Complexity: O(1)
- @inlinable public
- init(slice:Bytes)
- {
- self.slice = slice
- }
- }
-}
-extension BSON.DocumentView:Equatable
-{
- /// Performs an exact byte-wise comparison on two lists.
- /// Does not parse or validate the operands.
- @inlinable public static
- func == (lhs:Self, rhs:BSON.DocumentView>) -> Bool
- {
- lhs.slice.elementsEqual(rhs.slice)
- }
-}
-extension BSON.DocumentView:Sendable where Bytes:Sendable
-{
-}
-extension BSON.DocumentView:VariableLengthBSON
-{
- public
- typealias Frame = BSON.DocumentFrame
-
- /// Stores the argument in ``slice`` unchanged. Equivalent to ``init(slice:)``.
- ///
- /// > Complexity: O(1)
- @inlinable public
- init(slicing bytes:Bytes)
- {
- self.init(slice: bytes)
- }
-}
-extension BSON.DocumentView:BSONView
-{
- @inlinable public
- init(_ value:BSON.AnyValue) throws
- {
- self = try value.cast(with: \.document)
- }
-}
-extension BSON.DocumentView
-{
- /// Indicates if this document contains no fields.
- @inlinable public
- var isEmpty:Bool { self.slice.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.slice.count }
-}
diff --git a/Sources/BSONTypes/BSON.ListView.swift b/Sources/BSONTypes/BSON.ListView.swift
deleted file mode 100644
index ae8c877c..00000000
--- a/Sources/BSONTypes/BSON.ListView.swift
+++ /dev/null
@@ -1,77 +0,0 @@
-import BSONTraversal
-
-extension BSON
-{
- /// A BSON list. The backing storage of this type is opaque,
- /// permitting lazy parsing of its inline content.
- @frozen public
- struct ListView where Bytes:RandomAccessCollection
- {
- public
- let document:BSON.DocumentView
-
- @inlinable public
- init(slice:Bytes)
- {
- self.document = .init(slice: slice)
- }
- }
-}
-extension BSON.ListView:Equatable
-{
- /// Performs an exact byte-wise comparison on two lists.
- /// Does not parse or validate the operands.
- @inlinable public static
- func == (lhs:Self, rhs:BSON.ListView>) -> Bool
- {
- lhs.document == rhs.document
- }
-}
-extension BSON.ListView:Sendable where Bytes:Sendable
-{
-}
-extension BSON.ListView:VariableLengthBSON
-{
- public
- typealias Frame = BSON.DocumentFrame
-
- /// Stores the argument in ``slice`` unchanged. Equivalent to ``init(slice:)``.
- ///
- /// > Complexity: O(1)
- @inlinable public
- init(slicing bytes:Bytes)
- {
- self.init(slice: bytes)
- }
-}
-extension BSON.ListView:BSONView
-{
- @inlinable public
- init(_ value:BSON.AnyValue) throws
- {
- self = try value.cast(with: \.list)
- }
-}
-extension BSON.ListView
-{
- /// The raw data backing this list. This collection *does not*
- /// include the trailing null byte that appears after its inline
- /// elements list.
- @inlinable public
- var slice:Bytes { self.document.slice }
-
- /// Indicates if this list contains no elements.
- @inlinable public
- var isEmpty:Bool { self.slice.isEmpty }
-
- /// The length that would be encoded in this list’s prefixed header.
- /// Equal to ``size``.
- @inlinable public
- var header:Int32 { .init(self.size) }
-
- /// The size of this list 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.slice.count }
-}
diff --git a/Sources/BSONTypes/BSONView.swift b/Sources/BSONTypes/BSONView.swift
deleted file mode 100644
index 01a269af..00000000
--- a/Sources/BSONTypes/BSONView.swift
+++ /dev/null
@@ -1,17 +0,0 @@
-/// A type that can be (efficiently) decoded from a BSON variant value
-/// backed by a preferred type of storage particular to the decoded type.
-///
-/// This protocol is parallel and unrelated to ``BSONDecodable`` to
-/// emphasize the performance characteristics of types that conform to
-/// this protocol and not ``BSONDecodable``.
-public
-protocol BSONView:Equatable
-{
- /// The backing storage used by this type. It is recommended that
- /// implementations satisfy this with generics.
- associatedtype Bytes:RandomAccessCollection
-
- /// Attempts to cast a BSON variant backed by ``Bytes`` to an instance
- /// of this view type without copying the contents of the backing storage.
- init(_:BSON.AnyValue) throws
-}
diff --git a/Sources/BSON_Durations/Milliseconds (ext).swift b/Sources/BSON_Durations/Milliseconds (ext).swift
index 5877bd0f..d95501b4 100644
--- a/Sources/BSON_Durations/Milliseconds (ext).swift
+++ b/Sources/BSON_Durations/Milliseconds (ext).swift
@@ -1,5 +1,4 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
import Durations
extension Milliseconds:BSONDecodable, BSONEncodable
diff --git a/Sources/BSON_Durations/Minutes (ext).swift b/Sources/BSON_Durations/Minutes (ext).swift
index 0f3f2425..94786302 100644
--- a/Sources/BSON_Durations/Minutes (ext).swift
+++ b/Sources/BSON_Durations/Minutes (ext).swift
@@ -1,5 +1,4 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
import Durations
extension Minutes:BSONDecodable, BSONEncodable
diff --git a/Sources/BSON_Durations/Seconds (ext).swift b/Sources/BSON_Durations/Seconds (ext).swift
index 75a19d50..0125adf6 100644
--- a/Sources/BSON_Durations/Seconds (ext).swift
+++ b/Sources/BSON_Durations/Seconds (ext).swift
@@ -1,5 +1,4 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
import Durations
extension Seconds:BSONDecodable, BSONEncodable
diff --git a/Sources/BSON_OrderedCollections/OrderedDictionary (ext).swift b/Sources/BSON_OrderedCollections/OrderedDictionary (ext).swift
index 9d538c05..e73424ce 100644
--- a/Sources/BSON_OrderedCollections/OrderedDictionary (ext).swift
+++ b/Sources/BSON_OrderedCollections/OrderedDictionary (ext).swift
@@ -1,5 +1,4 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
import OrderedCollections
extension OrderedDictionary:BSONDocumentViewDecodable, BSONDecodable
@@ -11,7 +10,7 @@ extension OrderedDictionary:BSONDocumentViewDecodable, BSONDecodable
self.init()
try bson.parse
{
- (field:BSON.ExplicitField) in
+ (field:BSON.FieldDecoder) in
if case _? = self.updateValue(try field.decode(to: Value.self),
forKey: field.key.rawValue)
diff --git a/Sources/BSON_UUID/UUID (ext).swift b/Sources/BSON_UUID/UUID (ext).swift
index fa84f444..b5946787 100644
--- a/Sources/BSON_UUID/UUID (ext).swift
+++ b/Sources/BSON_UUID/UUID (ext).swift
@@ -1,6 +1,5 @@
+import BSON
import UUID
-import BSONDecoding
-import BSONEncoding
extension UUID:BSONDecodable, BSONBinaryViewDecodable
{
@@ -16,7 +15,7 @@ extension UUID:BSONDecodable, BSONBinaryViewDecodable
extension UUID:BSONEncodable
{
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
field.encode(binary: .init(subtype: .uuid, slice: self))
}
diff --git a/Sources/Mongo/README.md b/Sources/Mongo/README.md
new file mode 100644
index 00000000..b0f7f587
--- /dev/null
+++ b/Sources/Mongo/README.md
@@ -0,0 +1,3 @@
+# ``Mongo``
+
+A single-type module that declares the ``Mongo`` namespace.
diff --git a/Sources/MongoSchema/Mongo.Collection.swift b/Sources/MongoABI/Modeling/Mongo.Collection.swift
similarity index 94%
rename from Sources/MongoSchema/Mongo.Collection.swift
rename to Sources/MongoABI/Modeling/Mongo.Collection.swift
index 4c7ae9e1..4d1958e5 100644
--- a/Sources/MongoSchema/Mongo.Collection.swift
+++ b/Sources/MongoABI/Modeling/Mongo.Collection.swift
@@ -1,5 +1,4 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoSchema/Mongo.Database.swift b/Sources/MongoABI/Modeling/Mongo.Database.swift
similarity index 95%
rename from Sources/MongoSchema/Mongo.Database.swift
rename to Sources/MongoABI/Modeling/Mongo.Database.swift
index 450ac127..34cb16bb 100644
--- a/Sources/MongoSchema/Mongo.Database.swift
+++ b/Sources/MongoABI/Modeling/Mongo.Database.swift
@@ -1,5 +1,4 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoSchema/Mongo.Namespaced.swift b/Sources/MongoABI/Modeling/Mongo.Namespaced.swift
similarity index 97%
rename from Sources/MongoSchema/Mongo.Namespaced.swift
rename to Sources/MongoABI/Modeling/Mongo.Namespaced.swift
index ec7b6071..50a87b68 100644
--- a/Sources/MongoSchema/Mongo.Namespaced.swift
+++ b/Sources/MongoABI/Modeling/Mongo.Namespaced.swift
@@ -1,5 +1,4 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoSchema/Mongo.KeyPath.swift b/Sources/MongoABI/Mongo.KeyPath.swift
similarity index 97%
rename from Sources/MongoSchema/Mongo.KeyPath.swift
rename to Sources/MongoABI/Mongo.KeyPath.swift
index cca78ef0..2eb931fe 100644
--- a/Sources/MongoSchema/Mongo.KeyPath.swift
+++ b/Sources/MongoABI/Mongo.KeyPath.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoSchema/Mongo.Variable.swift b/Sources/MongoABI/Mongo.Variable.swift
similarity index 97%
rename from Sources/MongoSchema/Mongo.Variable.swift
rename to Sources/MongoABI/Mongo.Variable.swift
index fc13064f..6d3fe880 100644
--- a/Sources/MongoSchema/Mongo.Variable.swift
+++ b/Sources/MongoABI/Mongo.Variable.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoSchema/MongoMasterCodingModel.swift b/Sources/MongoABI/MongoMasterCodingModel.swift
similarity index 92%
rename from Sources/MongoSchema/MongoMasterCodingModel.swift
rename to Sources/MongoABI/MongoMasterCodingModel.swift
index 022b37fc..a7c749a2 100644
--- a/Sources/MongoSchema/MongoMasterCodingModel.swift
+++ b/Sources/MongoABI/MongoMasterCodingModel.swift
@@ -5,7 +5,7 @@
/// representations. A master coding model is a type that defines the full set of
/// coding keys used to encode the documents.
public
-protocol MongoMasterCodingModel
+protocol MongoMasterCodingModel
{
associatedtype CodingKey:RawRepresentable
}
diff --git a/Sources/MongoDriver/Outlining/Mongo.OutlineType.swift b/Sources/MongoABI/Outlining/Mongo.OutlineType.swift
similarity index 100%
rename from Sources/MongoDriver/Outlining/Mongo.OutlineType.swift
rename to Sources/MongoABI/Outlining/Mongo.OutlineType.swift
diff --git a/Sources/MongoDriver/Outlining/Mongo.OutlineVector.swift b/Sources/MongoABI/Outlining/Mongo.OutlineVector.swift
similarity index 58%
rename from Sources/MongoDriver/Outlining/Mongo.OutlineVector.swift
rename to Sources/MongoABI/Outlining/Mongo.OutlineVector.swift
index 585b3760..165e044f 100644
--- a/Sources/MongoDriver/Outlining/Mongo.OutlineVector.swift
+++ b/Sources/MongoABI/Outlining/Mongo.OutlineVector.swift
@@ -1,4 +1,4 @@
-import MongoWire
+import BSON
extension Mongo
{
@@ -6,14 +6,14 @@ extension Mongo
struct OutlineVector:Sendable
{
public
- let documents:OutlineDocuments
+ let bson:BSON.Output<[UInt8]>
public
let type:OutlineType
@inlinable public
- init(_ documents:OutlineDocuments, type:OutlineType)
+ init(bson:BSON.Output<[UInt8]>, type:OutlineType)
{
- self.documents = documents
+ self.bson = bson
self.type = type
}
}
diff --git a/Sources/MongoSchema/exports.swift b/Sources/MongoABI/exports.swift
similarity index 100%
rename from Sources/MongoSchema/exports.swift
rename to Sources/MongoABI/exports.swift
diff --git a/Sources/MongoBuiltins/Accumulators/Mongo.Accumulator.Superlative.swift b/Sources/MongoBuiltins/Accumulators/Mongo.Accumulator.Superlative.swift
index d3538fd3..c51a2346 100644
--- a/Sources/MongoBuiltins/Accumulators/Mongo.Accumulator.Superlative.swift
+++ b/Sources/MongoBuiltins/Accumulators/Mongo.Accumulator.Superlative.swift
@@ -16,10 +16,10 @@ extension Mongo.Accumulator.Superlative
{
switch self
{
- case .first: return "$firstN"
- case .last: return "$lastN"
- case .max: return "$maxN"
- case .min: return "$minN"
+ case .first: "$firstN"
+ case .last: "$lastN"
+ case .max: "$maxN"
+ case .min: "$minN"
}
}
}
diff --git a/Sources/MongoBuiltins/Accumulators/Mongo.Accumulator.SuperlativeDocument.swift b/Sources/MongoBuiltins/Accumulators/Mongo.Accumulator.SuperlativeDocument.swift
index 5bd9b423..d1dd1725 100644
--- a/Sources/MongoBuiltins/Accumulators/Mongo.Accumulator.SuperlativeDocument.swift
+++ b/Sources/MongoBuiltins/Accumulators/Mongo.Accumulator.SuperlativeDocument.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo.Accumulator
{
diff --git a/Sources/MongoBuiltins/Accumulators/Mongo.Accumulator.SuperlativeSort.swift b/Sources/MongoBuiltins/Accumulators/Mongo.Accumulator.SuperlativeSort.swift
index d85e2ed2..0e3270f4 100644
--- a/Sources/MongoBuiltins/Accumulators/Mongo.Accumulator.SuperlativeSort.swift
+++ b/Sources/MongoBuiltins/Accumulators/Mongo.Accumulator.SuperlativeSort.swift
@@ -14,8 +14,8 @@ extension Mongo.Accumulator.SuperlativeSort
{
switch self
{
- case .bottom: return "$bottomN"
- case .top: return "$topN"
+ case .bottom: "$bottomN"
+ case .top: "$topN"
}
}
}
diff --git a/Sources/MongoBuiltins/Accumulators/Mongo.Accumulator.SuperlativeSortDocument.swift b/Sources/MongoBuiltins/Accumulators/Mongo.Accumulator.SuperlativeSortDocument.swift
index 8d0610bc..493a596d 100644
--- a/Sources/MongoBuiltins/Accumulators/Mongo.Accumulator.SuperlativeSortDocument.swift
+++ b/Sources/MongoBuiltins/Accumulators/Mongo.Accumulator.SuperlativeSortDocument.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo.Accumulator
{
diff --git a/Sources/MongoBuiltins/Accumulators/Mongo.Accumulator.swift b/Sources/MongoBuiltins/Accumulators/Mongo.Accumulator.swift
index 7b4ae9ba..7f5e0245 100644
--- a/Sources/MongoBuiltins/Accumulators/Mongo.Accumulator.swift
+++ b/Sources/MongoBuiltins/Accumulators/Mongo.Accumulator.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Expressions/BSONEncodable (ext).swift b/Sources/MongoBuiltins/BSONEncodable (ext).swift
similarity index 95%
rename from Sources/MongoBuiltins/Expressions/BSONEncodable (ext).swift
rename to Sources/MongoBuiltins/BSONEncodable (ext).swift
index 4dde63af..41ea372b 100644
--- a/Sources/MongoBuiltins/Expressions/BSONEncodable (ext).swift
+++ b/Sources/MongoBuiltins/BSONEncodable (ext).swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
// This must be an extension on ``Optional`` and not ``BSONEncodable``
// because SE-299 does not support protocol extension member lookup with
diff --git a/Sources/MongoBuiltins/Documents/Bucket/Mongo.BucketAutoDocument.swift b/Sources/MongoBuiltins/Documents/Bucket/Mongo.BucketAutoDocument.swift
index f605913f..df21dc7d 100644
--- a/Sources/MongoBuiltins/Documents/Bucket/Mongo.BucketAutoDocument.swift
+++ b/Sources/MongoBuiltins/Documents/Bucket/Mongo.BucketAutoDocument.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Bucket/Mongo.BucketDocument.swift b/Sources/MongoBuiltins/Documents/Bucket/Mongo.BucketDocument.swift
index 6b016896..9f3c280f 100644
--- a/Sources/MongoBuiltins/Documents/Bucket/Mongo.BucketDocument.swift
+++ b/Sources/MongoBuiltins/Documents/Bucket/Mongo.BucketDocument.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Bucket/Mongo.BucketOutputDocument.swift b/Sources/MongoBuiltins/Documents/Bucket/Mongo.BucketOutputDocument.swift
index bcba0380..a747a243 100644
--- a/Sources/MongoBuiltins/Documents/Bucket/Mongo.BucketOutputDocument.swift
+++ b/Sources/MongoBuiltins/Documents/Bucket/Mongo.BucketOutputDocument.swift
@@ -1,6 +1,5 @@
-import BSONDecoding
-import BSONEncoding
-import MongoSchema
+import BSON
+import MongoABI
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Bucket/Mongo.PreferredNumbers.swift b/Sources/MongoBuiltins/Documents/Bucket/Mongo.PreferredNumbers.swift
index e041be60..85fddf94 100644
--- a/Sources/MongoBuiltins/Documents/Bucket/Mongo.PreferredNumbers.swift
+++ b/Sources/MongoBuiltins/Documents/Bucket/Mongo.PreferredNumbers.swift
@@ -1,5 +1,4 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/CollectionStats/Mongo.CollectionStatsDocument.swift b/Sources/MongoBuiltins/Documents/CollectionStats/Mongo.CollectionStatsDocument.swift
index 1a03b4eb..45a055f4 100644
--- a/Sources/MongoBuiltins/Documents/CollectionStats/Mongo.CollectionStatsDocument.swift
+++ b/Sources/MongoBuiltins/Documents/CollectionStats/Mongo.CollectionStatsDocument.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/CollectionStats/Mongo.LatencyStatsDocument.swift b/Sources/MongoBuiltins/Documents/CollectionStats/Mongo.LatencyStatsDocument.swift
index 4b05187e..1003fc66 100644
--- a/Sources/MongoBuiltins/Documents/CollectionStats/Mongo.LatencyStatsDocument.swift
+++ b/Sources/MongoBuiltins/Documents/CollectionStats/Mongo.LatencyStatsDocument.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/CollectionStats/Mongo.StorageStatsDocument.swift b/Sources/MongoBuiltins/Documents/CollectionStats/Mongo.StorageStatsDocument.swift
index 02d19a8f..b0931cc1 100644
--- a/Sources/MongoBuiltins/Documents/CollectionStats/Mongo.StorageStatsDocument.swift
+++ b/Sources/MongoBuiltins/Documents/CollectionStats/Mongo.StorageStatsDocument.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/CurrentOperation/Mongo.CurrentOperationDocument.swift b/Sources/MongoBuiltins/Documents/CurrentOperation/Mongo.CurrentOperationDocument.swift
index 23dbacda..c9d00a89 100644
--- a/Sources/MongoBuiltins/Documents/CurrentOperation/Mongo.CurrentOperationDocument.swift
+++ b/Sources/MongoBuiltins/Documents/CurrentOperation/Mongo.CurrentOperationDocument.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Facet/Mongo.FacetDocument.swift b/Sources/MongoBuiltins/Documents/Facet/Mongo.FacetDocument.swift
index 4eeba6fb..577e491a 100644
--- a/Sources/MongoBuiltins/Documents/Facet/Mongo.FacetDocument.swift
+++ b/Sources/MongoBuiltins/Documents/Facet/Mongo.FacetDocument.swift
@@ -1,5 +1,5 @@
-import BSONEncoding
-import MongoSchema
+import BSON
+import MongoABI
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Filter/Mongo.FilterDocument.swift b/Sources/MongoBuiltins/Documents/Filter/Mongo.FilterDocument.swift
index 9cb9491c..3747af05 100644
--- a/Sources/MongoBuiltins/Documents/Filter/Mongo.FilterDocument.swift
+++ b/Sources/MongoBuiltins/Documents/Filter/Mongo.FilterDocument.swift
@@ -1,5 +1,5 @@
-import BSONEncoding
-import MongoSchema
+import BSON
+import MongoABI
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Group/Mongo.GroupDocument.swift b/Sources/MongoBuiltins/Documents/Group/Mongo.GroupDocument.swift
index 7828ad3a..6b604a50 100644
--- a/Sources/MongoBuiltins/Documents/Group/Mongo.GroupDocument.swift
+++ b/Sources/MongoBuiltins/Documents/Group/Mongo.GroupDocument.swift
@@ -1,5 +1,5 @@
-import BSONEncoding
-import MongoSchema
+import BSON
+import MongoABI
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Let/Mongo.LetDocument.swift b/Sources/MongoBuiltins/Documents/Let/Mongo.LetDocument.swift
index 8a289d14..b3e09e6a 100644
--- a/Sources/MongoBuiltins/Documents/Let/Mongo.LetDocument.swift
+++ b/Sources/MongoBuiltins/Documents/Let/Mongo.LetDocument.swift
@@ -1,5 +1,5 @@
-import BSONEncoding
-import MongoSchema
+import BSON
+import MongoABI
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Lookup/Mongo.LookupDocument.swift b/Sources/MongoBuiltins/Documents/Lookup/Mongo.LookupDocument.swift
index 76244abf..d5988324 100644
--- a/Sources/MongoBuiltins/Documents/Lookup/Mongo.LookupDocument.swift
+++ b/Sources/MongoBuiltins/Documents/Lookup/Mongo.LookupDocument.swift
@@ -1,5 +1,5 @@
-import BSONEncoding
-import MongoSchema
+import BSON
+import MongoABI
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Map/Mongo.MapDocument.swift b/Sources/MongoBuiltins/Documents/Map/Mongo.MapDocument.swift
index be855233..b604e84f 100644
--- a/Sources/MongoBuiltins/Documents/Map/Mongo.MapDocument.swift
+++ b/Sources/MongoBuiltins/Documents/Map/Mongo.MapDocument.swift
@@ -1,6 +1,5 @@
-import BSONDecoding
-import BSONEncoding
-import MongoSchema
+import BSON
+import MongoABI
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Merge/Mongo.MergeDocument.swift b/Sources/MongoBuiltins/Documents/Merge/Mongo.MergeDocument.swift
index ff6c8ab5..63430390 100644
--- a/Sources/MongoBuiltins/Documents/Merge/Mongo.MergeDocument.swift
+++ b/Sources/MongoBuiltins/Documents/Merge/Mongo.MergeDocument.swift
@@ -1,5 +1,5 @@
-import BSONEncoding
-import MongoSchema
+import BSON
+import MongoABI
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Merge/Mongo.MergeInsertMode.swift b/Sources/MongoBuiltins/Documents/Merge/Mongo.MergeInsertMode.swift
index 70683eb7..57d03194 100644
--- a/Sources/MongoBuiltins/Documents/Merge/Mongo.MergeInsertMode.swift
+++ b/Sources/MongoBuiltins/Documents/Merge/Mongo.MergeInsertMode.swift
@@ -1,5 +1,4 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Merge/Mongo.MergeUpdateMode.swift b/Sources/MongoBuiltins/Documents/Merge/Mongo.MergeUpdateMode.swift
index 1462264a..102a782b 100644
--- a/Sources/MongoBuiltins/Documents/Merge/Mongo.MergeUpdateMode.swift
+++ b/Sources/MongoBuiltins/Documents/Merge/Mongo.MergeUpdateMode.swift
@@ -1,5 +1,4 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Mongo.KeyPath (ext).swift b/Sources/MongoBuiltins/Documents/Mongo.KeyPath (ext).swift
index db4c5b16..ba1fe3a3 100644
--- a/Sources/MongoBuiltins/Documents/Mongo.KeyPath (ext).swift
+++ b/Sources/MongoBuiltins/Documents/Mongo.KeyPath (ext).swift
@@ -1,4 +1,4 @@
-import MongoSchema
+import MongoABI
extension Mongo.KeyPath:_MongoExpressionRestrictedEncodable
{
diff --git a/Sources/MongoBuiltins/Documents/Mongo.Variable (ext).swift b/Sources/MongoBuiltins/Documents/Mongo.Variable (ext).swift
index 626716ae..9a248708 100644
--- a/Sources/MongoBuiltins/Documents/Mongo.Variable (ext).swift
+++ b/Sources/MongoBuiltins/Documents/Mongo.Variable (ext).swift
@@ -1,4 +1,4 @@
-import MongoSchema
+import MongoABI
extension Mongo.Variable:_MongoExpressionRestrictedEncodable
{
diff --git a/Sources/MongoBuiltins/Documents/MongoDocumentDSL.swift b/Sources/MongoBuiltins/Documents/MongoDocumentDSL.swift
index 53dcd178..983af228 100644
--- a/Sources/MongoBuiltins/Documents/MongoDocumentDSL.swift
+++ b/Sources/MongoBuiltins/Documents/MongoDocumentDSL.swift
@@ -1,5 +1,4 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
/// A `MongoDocumentDSL` is nothing more than a type that supports an
/// ``init(with:)`` builder API.
diff --git a/Sources/MongoBuiltins/Documents/MongoListDSL.swift b/Sources/MongoBuiltins/Documents/MongoListDSL.swift
index 023e6fd1..0b1221a1 100644
--- a/Sources/MongoBuiltins/Documents/MongoListDSL.swift
+++ b/Sources/MongoBuiltins/Documents/MongoListDSL.swift
@@ -1,5 +1,4 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
/// A `MongoListDSL` is nothing more than a type that supports an
/// ``init(with:)`` builder API.
@@ -9,7 +8,7 @@ import BSONEncoding
public
protocol MongoListDSL:BSONRepresentable, BSONDecodable, BSONEncodable
{
- associatedtype Encoder:BSONEncoder
+ associatedtype Encoder:BSON.Encoder
}
extension MongoListDSL
{
diff --git a/Sources/MongoBuiltins/Documents/Predicate/Mongo.PredicateDocument.swift b/Sources/MongoBuiltins/Documents/Predicate/Mongo.PredicateDocument.swift
index a1438c5f..116a1062 100644
--- a/Sources/MongoBuiltins/Documents/Predicate/Mongo.PredicateDocument.swift
+++ b/Sources/MongoBuiltins/Documents/Predicate/Mongo.PredicateDocument.swift
@@ -1,5 +1,5 @@
-import BSONEncoding
-import MongoSchema
+import BSON
+import MongoABI
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Predicate/Mongo.PredicateList.swift b/Sources/MongoBuiltins/Documents/Predicate/Mongo.PredicateList.swift
index 272d08ee..13b1ca42 100644
--- a/Sources/MongoBuiltins/Documents/Predicate/Mongo.PredicateList.swift
+++ b/Sources/MongoBuiltins/Documents/Predicate/Mongo.PredicateList.swift
@@ -1,5 +1,4 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Predicate/Mongo.PredicateListEncoder.swift b/Sources/MongoBuiltins/Documents/Predicate/Mongo.PredicateListEncoder.swift
index 2fbb7130..9c07beb2 100644
--- a/Sources/MongoBuiltins/Documents/Predicate/Mongo.PredicateListEncoder.swift
+++ b/Sources/MongoBuiltins/Documents/Predicate/Mongo.PredicateListEncoder.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo
{
@@ -15,7 +15,7 @@ extension Mongo
}
}
}
-extension Mongo.PredicateListEncoder:BSONEncoder
+extension Mongo.PredicateListEncoder:BSON.Encoder
{
@inlinable public
init(_ output:consuming BSON.Output<[UInt8]>)
@@ -27,7 +27,7 @@ extension Mongo.PredicateListEncoder:BSONEncoder
func move() -> BSON.Output<[UInt8]> { self.list.move() }
@inlinable public static
- var type:BSON { .list }
+ var type:BSON.AnyType { .list }
}
extension Mongo.PredicateListEncoder
{
diff --git a/Sources/MongoBuiltins/Documents/Predicate/Mongo.PredicateOperator.swift b/Sources/MongoBuiltins/Documents/Predicate/Mongo.PredicateOperator.swift
index 701d72a3..5125b622 100644
--- a/Sources/MongoBuiltins/Documents/Predicate/Mongo.PredicateOperator.swift
+++ b/Sources/MongoBuiltins/Documents/Predicate/Mongo.PredicateOperator.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo
{
@@ -30,7 +30,7 @@ extension Mongo.PredicateOperator
}
}
@inlinable public
- subscript(key:Metatype) -> BSON?
+ subscript(key:Metatype) -> BSON.AnyType?
{
get
{
@@ -42,7 +42,7 @@ extension Mongo.PredicateOperator
}
}
@inlinable public
- subscript(key:Metatype) -> [BSON]?
+ subscript(key:Metatype) -> [BSON.AnyType]?
{
get
{
diff --git a/Sources/MongoBuiltins/Documents/Projection/Mongo.ProjectionDocument.swift b/Sources/MongoBuiltins/Documents/Projection/Mongo.ProjectionDocument.swift
index f7d73a3e..3276f4b5 100644
--- a/Sources/MongoBuiltins/Documents/Projection/Mongo.ProjectionDocument.swift
+++ b/Sources/MongoBuiltins/Documents/Projection/Mongo.ProjectionDocument.swift
@@ -1,5 +1,5 @@
-import BSONEncoding
-import MongoSchema
+import BSON
+import MongoABI
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Projection/Mongo.ProjectionOperator.Metadata.swift b/Sources/MongoBuiltins/Documents/Projection/Mongo.ProjectionOperator.Metadata.swift
index 42dc58df..551a14e9 100644
--- a/Sources/MongoBuiltins/Documents/Projection/Mongo.ProjectionOperator.Metadata.swift
+++ b/Sources/MongoBuiltins/Documents/Projection/Mongo.ProjectionOperator.Metadata.swift
@@ -1,5 +1,4 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
extension Mongo.ProjectionOperator
{
diff --git a/Sources/MongoBuiltins/Documents/Projection/Mongo.ProjectionOperator.swift b/Sources/MongoBuiltins/Documents/Projection/Mongo.ProjectionOperator.swift
index f80fcee6..a8b64c3f 100644
--- a/Sources/MongoBuiltins/Documents/Projection/Mongo.ProjectionOperator.swift
+++ b/Sources/MongoBuiltins/Documents/Projection/Mongo.ProjectionOperator.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Reduce/Mongo.ReduceDocument.swift b/Sources/MongoBuiltins/Documents/Reduce/Mongo.ReduceDocument.swift
index 99eb3a09..e414bc34 100644
--- a/Sources/MongoBuiltins/Documents/Reduce/Mongo.ReduceDocument.swift
+++ b/Sources/MongoBuiltins/Documents/Reduce/Mongo.ReduceDocument.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Sample/Mongo.SampleDocument.swift b/Sources/MongoBuiltins/Documents/Sample/Mongo.SampleDocument.swift
index fadbb0a6..1f5c8110 100644
--- a/Sources/MongoBuiltins/Documents/Sample/Mongo.SampleDocument.swift
+++ b/Sources/MongoBuiltins/Documents/Sample/Mongo.SampleDocument.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Set/Mongo.SetDocument.swift b/Sources/MongoBuiltins/Documents/Set/Mongo.SetDocument.swift
index 0119ac1f..f66b2510 100644
--- a/Sources/MongoBuiltins/Documents/Set/Mongo.SetDocument.swift
+++ b/Sources/MongoBuiltins/Documents/Set/Mongo.SetDocument.swift
@@ -1,5 +1,5 @@
-import BSONEncoding
-import MongoSchema
+import BSON
+import MongoABI
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Sort/Mongo.SortDocument.swift b/Sources/MongoBuiltins/Documents/Sort/Mongo.SortDocument.swift
index 67c456fa..02966c83 100644
--- a/Sources/MongoBuiltins/Documents/Sort/Mongo.SortDocument.swift
+++ b/Sources/MongoBuiltins/Documents/Sort/Mongo.SortDocument.swift
@@ -1,5 +1,5 @@
-import BSONEncoding
-import MongoSchema
+import BSON
+import MongoABI
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Sort/Mongo.SortOperator.Metadata.swift b/Sources/MongoBuiltins/Documents/Sort/Mongo.SortOperator.Metadata.swift
index 85fa93c4..d61f0dc2 100644
--- a/Sources/MongoBuiltins/Documents/Sort/Mongo.SortOperator.Metadata.swift
+++ b/Sources/MongoBuiltins/Documents/Sort/Mongo.SortOperator.Metadata.swift
@@ -1,5 +1,4 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
extension Mongo.SortOperator
{
diff --git a/Sources/MongoBuiltins/Documents/Sort/Mongo.SortOperator.swift b/Sources/MongoBuiltins/Documents/Sort/Mongo.SortOperator.swift
index 28576d82..16051b08 100644
--- a/Sources/MongoBuiltins/Documents/Sort/Mongo.SortOperator.swift
+++ b/Sources/MongoBuiltins/Documents/Sort/Mongo.SortOperator.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/SortArray/Mongo.SortArrayDocument.swift b/Sources/MongoBuiltins/Documents/SortArray/Mongo.SortArrayDocument.swift
index 094cc045..345d62d9 100644
--- a/Sources/MongoBuiltins/Documents/SortArray/Mongo.SortArrayDocument.swift
+++ b/Sources/MongoBuiltins/Documents/SortArray/Mongo.SortArrayDocument.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Switch/Mongo.SwitchBranch.swift b/Sources/MongoBuiltins/Documents/Switch/Mongo.SwitchBranch.swift
index a54ae279..a10a4a2f 100644
--- a/Sources/MongoBuiltins/Documents/Switch/Mongo.SwitchBranch.swift
+++ b/Sources/MongoBuiltins/Documents/Switch/Mongo.SwitchBranch.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Switch/Mongo.SwitchBranches.Encoder.swift b/Sources/MongoBuiltins/Documents/Switch/Mongo.SwitchBranches.Encoder.swift
index e61565e7..70e8509f 100644
--- a/Sources/MongoBuiltins/Documents/Switch/Mongo.SwitchBranches.Encoder.swift
+++ b/Sources/MongoBuiltins/Documents/Switch/Mongo.SwitchBranches.Encoder.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo.SwitchBranches
{
@@ -15,7 +15,7 @@ extension Mongo.SwitchBranches
}
}
}
-extension Mongo.SwitchBranches.Encoder:BSONEncoder
+extension Mongo.SwitchBranches.Encoder:BSON.Encoder
{
@inlinable public
init(_ output:consuming BSON.Output<[UInt8]>)
@@ -27,7 +27,7 @@ extension Mongo.SwitchBranches.Encoder:BSONEncoder
func move() -> BSON.Output<[UInt8]> { self.list.move() }
@inlinable public static
- var type:BSON { .list }
+ var type:BSON.AnyType { .list }
}
extension Mongo.SwitchBranches.Encoder
{
diff --git a/Sources/MongoBuiltins/Documents/Switch/Mongo.SwitchDocument.swift b/Sources/MongoBuiltins/Documents/Switch/Mongo.SwitchDocument.swift
index beadd7db..4faa12ac 100644
--- a/Sources/MongoBuiltins/Documents/Switch/Mongo.SwitchDocument.swift
+++ b/Sources/MongoBuiltins/Documents/Switch/Mongo.SwitchDocument.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/UnionWith/Mongo.UnionWithDocument.swift b/Sources/MongoBuiltins/Documents/UnionWith/Mongo.UnionWithDocument.swift
index 66b8e775..5359e7f8 100644
--- a/Sources/MongoBuiltins/Documents/UnionWith/Mongo.UnionWithDocument.swift
+++ b/Sources/MongoBuiltins/Documents/UnionWith/Mongo.UnionWithDocument.swift
@@ -1,5 +1,5 @@
-import BSONEncoding
-import MongoSchema
+import BSON
+import MongoABI
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Unwind/Mongo.UnwindDocument.swift b/Sources/MongoBuiltins/Documents/Unwind/Mongo.UnwindDocument.swift
index 5d9eafc8..8dd03489 100644
--- a/Sources/MongoBuiltins/Documents/Unwind/Mongo.UnwindDocument.swift
+++ b/Sources/MongoBuiltins/Documents/Unwind/Mongo.UnwindDocument.swift
@@ -1,5 +1,5 @@
-import BSONEncoding
-import MongoSchema
+import BSON
+import MongoABI
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Update/Mongo.UpdateBitwiseOperator.swift b/Sources/MongoBuiltins/Documents/Update/Mongo.UpdateBitwiseOperator.swift
index d0ab6c04..1927fd46 100644
--- a/Sources/MongoBuiltins/Documents/Update/Mongo.UpdateBitwiseOperator.swift
+++ b/Sources/MongoBuiltins/Documents/Update/Mongo.UpdateBitwiseOperator.swift
@@ -1,5 +1,4 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Update/Mongo.UpdateDocument.Unset.swift b/Sources/MongoBuiltins/Documents/Update/Mongo.UpdateDocument.Unset.swift
index 140a5d89..053c204c 100644
--- a/Sources/MongoBuiltins/Documents/Update/Mongo.UpdateDocument.Unset.swift
+++ b/Sources/MongoBuiltins/Documents/Update/Mongo.UpdateDocument.Unset.swift
@@ -1,7 +1,7 @@
extension Mongo.UpdateDocument
{
/// Takes a document and removes the specified fields.
- /// Not to be confused with the ``Mongo.PipelineState.Unset unset``
+ /// Not to be confused with the ``Mongo.PipelineState.Unset/unset``
/// aggregation pipeline stage, which can take a field path directly.
@frozen public
enum Unset:String, Hashable, Sendable
diff --git a/Sources/MongoBuiltins/Documents/Update/Mongo.UpdateDocument.swift b/Sources/MongoBuiltins/Documents/Update/Mongo.UpdateDocument.swift
index f1f0e36b..ca7d1ce6 100644
--- a/Sources/MongoBuiltins/Documents/Update/Mongo.UpdateDocument.swift
+++ b/Sources/MongoBuiltins/Documents/Update/Mongo.UpdateDocument.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Update/Mongo.UpdateFields.swift b/Sources/MongoBuiltins/Documents/Update/Mongo.UpdateFields.swift
index 09626da1..ad7c1c7d 100644
--- a/Sources/MongoBuiltins/Documents/Update/Mongo.UpdateFields.swift
+++ b/Sources/MongoBuiltins/Documents/Update/Mongo.UpdateFields.swift
@@ -1,5 +1,5 @@
-import BSONEncoding
-import MongoSchema
+import BSON
+import MongoABI
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Update/Mongo.UpdatePosition.swift b/Sources/MongoBuiltins/Documents/Update/Mongo.UpdatePosition.swift
index 43a55f03..e2910a7e 100644
--- a/Sources/MongoBuiltins/Documents/Update/Mongo.UpdatePosition.swift
+++ b/Sources/MongoBuiltins/Documents/Update/Mongo.UpdatePosition.swift
@@ -1,5 +1,4 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Documents/Zip/Mongo.ZipDocument.swift b/Sources/MongoBuiltins/Documents/Zip/Mongo.ZipDocument.swift
index 709d7b82..a780f3f6 100644
--- a/Sources/MongoBuiltins/Documents/Zip/Mongo.ZipDocument.swift
+++ b/Sources/MongoBuiltins/Documents/Zip/Mongo.ZipDocument.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension Mongo
{
@@ -92,7 +92,7 @@ extension Mongo.ZipDocument
}
/// This subscript automatically sets `useLongestLength` if set to a
- /// non-[`nil`]() value.
+ /// non-nil value.
@inlinable public
subscript(key:Defaults) -> Encodable?
where Encodable:BSONEncodable
diff --git a/Sources/MongoBuiltins/Documents/_MongoExpressionRestrictedEncodable.swift b/Sources/MongoBuiltins/Documents/_MongoExpressionRestrictedEncodable.swift
index 66f7689f..a16010bf 100644
--- a/Sources/MongoBuiltins/Documents/_MongoExpressionRestrictedEncodable.swift
+++ b/Sources/MongoBuiltins/Documents/_MongoExpressionRestrictedEncodable.swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
/// This protocol provides diagnostics to help you avoid common mistakes, such as
/// using keypaths or expression variables at the top-level of a ``Mongo.PredicateDocument``.
diff --git a/Sources/MongoBuiltins/Expressions/BSON.ListEncoder (ext).swift b/Sources/MongoBuiltins/Expressions/BSON.ListEncoder (ext).swift
index 9950d85f..c408634c 100644
--- a/Sources/MongoBuiltins/Expressions/BSON.ListEncoder (ext).swift
+++ b/Sources/MongoBuiltins/Expressions/BSON.ListEncoder (ext).swift
@@ -1,4 +1,4 @@
-import BSONEncoding
+import BSON
extension BSON.ListEncoder
{
diff --git a/Sources/MongoBuiltins/Expressions/Mongo.Expression.swift b/Sources/MongoBuiltins/Expressions/Mongo.Expression.swift
index f03de21d..a99ade85 100644
--- a/Sources/MongoBuiltins/Expressions/Mongo.Expression.swift
+++ b/Sources/MongoBuiltins/Expressions/Mongo.Expression.swift
@@ -1,5 +1,4 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
@available(*, deprecated, renamed: "Mongo.Expression")
public
diff --git a/Sources/MongoBuiltins/Expressions/Optional (ext).swift b/Sources/MongoBuiltins/Expressions/Optional (ext).swift
index f4f7e3d8..3e4c2ec0 100644
--- a/Sources/MongoBuiltins/Expressions/Optional (ext).swift
+++ b/Sources/MongoBuiltins/Expressions/Optional (ext).swift
@@ -5,6 +5,6 @@ extension Mongo.Expression?
@inlinable public static
func expr(with populate:(inout Mongo.Expression) throws -> ()) rethrows -> Self
{
- return .some(try .expr(with: populate))
+ .some(try .expr(with: populate))
}
}
diff --git a/Sources/MongoBuiltins/Mongo.List.swift b/Sources/MongoBuiltins/Mongo.List.swift
index 6dc84c10..c4adab2a 100644
--- a/Sources/MongoBuiltins/Mongo.List.swift
+++ b/Sources/MongoBuiltins/Mongo.List.swift
@@ -1,5 +1,5 @@
-import BSONEncoding
-import MongoSchema
+import BSON
+import MongoABI
extension Mongo
{
diff --git a/Sources/MongoBuiltins/Mongo.Namespaced (ext).swift b/Sources/MongoBuiltins/Mongo.Namespaced (ext).swift
index e3c39037..c9f533a9 100644
--- a/Sources/MongoBuiltins/Mongo.Namespaced (ext).swift
+++ b/Sources/MongoBuiltins/Mongo.Namespaced (ext).swift
@@ -1,5 +1,5 @@
import BSON
-import MongoSchema
+import MongoABI
extension Mongo.Namespaced
{
diff --git a/Sources/MongoBuiltins/Pipelines/Mongo.Pipeline.swift b/Sources/MongoBuiltins/Pipelines/Mongo.Pipeline.swift
index cccead13..979331a4 100644
--- a/Sources/MongoBuiltins/Pipelines/Mongo.Pipeline.swift
+++ b/Sources/MongoBuiltins/Pipelines/Mongo.Pipeline.swift
@@ -1,7 +1,5 @@
-import BSONDecoding
-import BSONEncoding
import BSON
-import MongoSchema
+import MongoABI
extension Mongo
{
@@ -38,7 +36,7 @@ extension Mongo.Pipeline:BSONDecodable
extension Mongo.Pipeline:BSONEncodable
{
@inlinable public
- func encode(to field:inout BSON.Field)
+ func encode(to field:inout BSON.FieldEncoder)
{
self.bson.encode(to: &field)
}
diff --git a/Sources/MongoBuiltins/Pipelines/Mongo.PipelineEncoder.swift b/Sources/MongoBuiltins/Pipelines/Mongo.PipelineEncoder.swift
index 0257abb9..391e592c 100644
--- a/Sources/MongoBuiltins/Pipelines/Mongo.PipelineEncoder.swift
+++ b/Sources/MongoBuiltins/Pipelines/Mongo.PipelineEncoder.swift
@@ -1,7 +1,5 @@
-import BSONDecoding
-import BSONEncoding
import BSON
-import MongoSchema
+import MongoABI
extension Mongo
{
@@ -18,7 +16,7 @@ extension Mongo
}
}
}
-extension Mongo.PipelineEncoder:BSONEncoder
+extension Mongo.PipelineEncoder:BSON.Encoder
{
@inlinable public
init(_ output:consuming BSON.Output<[UInt8]>)
@@ -30,7 +28,7 @@ extension Mongo.PipelineEncoder:BSONEncoder
func move() -> BSON.Output<[UInt8]> { self.list.move() }
@inlinable public static
- var type:BSON { .list }
+ var type:BSON.AnyType { .list }
}
extension Mongo.PipelineEncoder
{
diff --git a/Sources/MongoClusters/ServerMetadata/Mongo.Replica.SecondaryBaseline.swift b/Sources/MongoClusters/ServerMetadata/Mongo.Replica.SecondaryBaseline.swift
index 61a8a46c..7d8702ac 100644
--- a/Sources/MongoClusters/ServerMetadata/Mongo.Replica.SecondaryBaseline.swift
+++ b/Sources/MongoClusters/ServerMetadata/Mongo.Replica.SecondaryBaseline.swift
@@ -40,6 +40,6 @@ extension Mongo.Replica.SecondaryBaseline
// we get rid of the “update” terms.
//
// (0 - candidate.write) - (0 - self.write)
- return .init(rawValue: self.write.value - candidate.write.value)
+ .init(rawValue: self.write.value - candidate.write.value)
}
}
diff --git a/Sources/MongoClusters/ServerMetadata/Mongo.Replica.Timings.swift b/Sources/MongoClusters/ServerMetadata/Mongo.Replica.Timings.swift
index bbf58d47..0521f821 100644
--- a/Sources/MongoClusters/ServerMetadata/Mongo.Replica.Timings.swift
+++ b/Sources/MongoClusters/ServerMetadata/Mongo.Replica.Timings.swift
@@ -1,4 +1,4 @@
-import BSONDecoding
+import BSON
extension Mongo.Replica
{
diff --git a/Sources/MongoClusters/ServerMetadata/Mongo.ServerDescription.swift b/Sources/MongoClusters/ServerMetadata/Mongo.ServerDescription.swift
index 51e8d183..ee416e9b 100644
--- a/Sources/MongoClusters/ServerMetadata/Mongo.ServerDescription.swift
+++ b/Sources/MongoClusters/ServerMetadata/Mongo.ServerDescription.swift
@@ -18,11 +18,11 @@ extension Mongo.ServerDescription
{
if case .connected(let metadata, _) = self
{
- return metadata
+ metadata
}
else
{
- return nil
+ nil
}
}
@inlinable public
@@ -30,11 +30,11 @@ extension Mongo.ServerDescription
{
if case .connected(_, let owner) = self
{
- return owner
+ owner
}
else
{
- return nil
+ nil
}
}
/// Returns the stored error, if this descriptor currently has one.
@@ -43,11 +43,11 @@ extension Mongo.ServerDescription
{
if case .errored(let error) = self
{
- return error
+ error
}
else
{
- return nil
+ nil
}
}
}
@@ -66,14 +66,14 @@ extension Mongo.ServerDescription
case .connected(_, let owner):
self = .connected(metadata, owner)
return .accepted
-
+
case .errored, .queued:
return .dropped
}
}
/// Places this descriptor in an ``case errored(_:)`` or ``case queued``
- /// state. If `status` is [`nil`]() and the descriptor is already in
+ /// state. If `status` is nil and the descriptor is already in
/// an errored state, the descriptor will remain in that state, and the
/// stored error will not be overwritten.
mutating
diff --git a/Sources/MongoClusters/ServerSelection/Mongo.Unreachable.swift b/Sources/MongoClusters/ServerSelection/Mongo.Unreachable.swift
index 4b0af72f..5626b809 100644
--- a/Sources/MongoClusters/ServerSelection/Mongo.Unreachable.swift
+++ b/Sources/MongoClusters/ServerSelection/Mongo.Unreachable.swift
@@ -18,18 +18,18 @@ extension Mongo.Unreachable:Equatable
switch (lhs, rhs)
{
case (.queued, .queued):
- return true
+ true
case (.errored(let lhs), .errored(let rhs)):
- return lhs == rhs
+ lhs == rhs
case (_, _):
- return false
+ false
}
}
}
extension Mongo.Unreachable
{
- /// Updates the stored error with the given error, if non-[`nil`]().
- /// If `status` is [`nil`]() and the descriptor is already in an
+ /// Updates the stored error with the given error, if non-nil.
+ /// If `status` is nil and the descriptor is already in an
/// errored state, the descriptor will remain in that state, and the
/// stored error will not be overwritten.
@inlinable public mutating
diff --git a/Sources/MongoClusters/Topologies/Mongo.Topology.Unknown.swift b/Sources/MongoClusters/Topologies/Mongo.Topology.Unknown.swift
index cde4fc87..f50bb744 100644
--- a/Sources/MongoClusters/Topologies/Mongo.Topology.Unknown.swift
+++ b/Sources/MongoClusters/Topologies/Mongo.Topology.Unknown.swift
@@ -27,11 +27,11 @@ extension Mongo.Topology.Unknown
{
if case ()? = self.ghosts[host]?.clear(status: status)
{
- return .accepted
+ .accepted
}
else
{
- return .rejected
+ .rejected
}
}
func topology(
@@ -42,25 +42,25 @@ extension Mongo.Topology.Unknown
switch $0
{
case .errored(let error):
- return .errored(error)
+ .errored(error)
case .queued:
- return .queued
+ .queued
}
}
}
- /// Removes the given host from the topology if present, returning [`true`]()
- /// if it was the only ghost in the topology. Returns [`false`]() otherwise.
+ /// Removes the given host from the topology if present, returning `true`
+ /// if it was the only ghost in the topology. Returns `false` otherwise.
@discardableResult
mutating
func pick(host:Mongo.Host) -> Bool
{
if case _? = self.ghosts.removeValue(forKey: host), self.ghosts.isEmpty
{
- return true
+ true
}
else
{
- return false
+ false
}
}
}
diff --git a/Sources/MongoClusters/TopologyUpdates/Mongo.Host.swift b/Sources/MongoClusters/TopologyUpdates/Mongo.Host.swift
index 54a2cdbb..d12d2f6c 100644
--- a/Sources/MongoClusters/TopologyUpdates/Mongo.Host.swift
+++ b/Sources/MongoClusters/TopologyUpdates/Mongo.Host.swift
@@ -1,22 +1,21 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
extension Mongo
{
- @frozen public
+ @frozen public
struct Host:Hashable, Sendable
{
- /// The hostname, such as [`"localhost"`](), [`"example.com"`](),
+ /// The hostname, such as [`"localhost"`](), [`"example.com"`](),
/// or [`"127.0.0.1"`]().
- public
+ public
var name:String
/// The port. The default MongoDB port is 27017.
- public
+ public
var port:Int
- @inlinable public
- init(name:String, port:Int? = nil)
+ @inlinable public
+ init(name:String, port:Int? = nil)
{
self.name = name
self.port = port ?? 27017
@@ -32,7 +31,7 @@ extension Mongo.Host:Comparable
}
}
extension Mongo.Host
-{
+{
// @inlinable public static
// func srv(_ name:String) -> Self
// {
diff --git a/Sources/MongoClusters/TopologyUpdates/Mongo.TopologyUpdate.Slave.swift b/Sources/MongoClusters/TopologyUpdates/Mongo.TopologyUpdate.Slave.swift
index 8cc344c2..c943aa58 100644
--- a/Sources/MongoClusters/TopologyUpdates/Mongo.TopologyUpdate.Slave.swift
+++ b/Sources/MongoClusters/TopologyUpdates/Mongo.TopologyUpdate.Slave.swift
@@ -16,9 +16,9 @@ extension Mongo.TopologyUpdate.Slave
{
switch self
{
- case .secondary(let replica): return .secondary(replica)
- case .arbiter: return .arbiter
- case .other: return .other
+ case .secondary(let replica): .secondary(replica)
+ case .arbiter: .arbiter
+ case .other: .other
}
}
}
diff --git a/Sources/MongoConfiguration/Authentication/Mongo.Authentication.SASL.swift b/Sources/MongoConfiguration/Authentication/Mongo.Authentication.SASL.swift
index 3b95cb3f..95969ef8 100644
--- a/Sources/MongoConfiguration/Authentication/Mongo.Authentication.SASL.swift
+++ b/Sources/MongoConfiguration/Authentication/Mongo.Authentication.SASL.swift
@@ -1,12 +1,11 @@
-import BSONDecoding
-import BSONEncoding
+import BSON
import Mongo
extension Mongo.Authentication
{
/// A namespace for SASL (Simple Authentication and Security Layer) types.
@frozen public
- enum SASL:String, Hashable, Sendable
+ enum SASL:String, Hashable, Sendable
{
case aws = "MONGODB-AWS"
case gssapi = "GSSAPI"
diff --git a/Sources/MongoConfiguration/Authentication/Mongo.Authentication.swift b/Sources/MongoConfiguration/Authentication/Mongo.Authentication.swift
index e4860ffb..6b117b6f 100644
--- a/Sources/MongoConfiguration/Authentication/Mongo.Authentication.swift
+++ b/Sources/MongoConfiguration/Authentication/Mongo.Authentication.swift
@@ -14,8 +14,8 @@ extension Mongo.Authentication:RawRepresentable
{
switch self
{
- case .sasl(let sasl): return sasl.rawValue
- case .x509: return "MONGODB-X509"
+ case .sasl(let sasl): sasl.rawValue
+ case .x509: "MONGODB-X509"
}
}
@inlinable public
diff --git a/Sources/MongoConfiguration/Authentication/Mongo.Credentials.swift b/Sources/MongoConfiguration/Authentication/Mongo.Credentials.swift
index 159e47b8..2afaede6 100644
--- a/Sources/MongoConfiguration/Authentication/Mongo.Credentials.swift
+++ b/Sources/MongoConfiguration/Authentication/Mongo.Credentials.swift
@@ -1,4 +1,4 @@
-import MongoSchema
+import MongoABI
extension Mongo
{
diff --git a/Sources/MongoConfiguration/Authentication/Mongo.User.swift b/Sources/MongoConfiguration/Authentication/Mongo.User.swift
index 4035d516..c1ee9e90 100644
--- a/Sources/MongoConfiguration/Authentication/Mongo.User.swift
+++ b/Sources/MongoConfiguration/Authentication/Mongo.User.swift
@@ -1,4 +1,4 @@
-import MongoSchema
+import MongoABI
extension Mongo
{
diff --git a/Sources/MongoConfiguration/URI/Mongo.URI.Authority.swift b/Sources/MongoConfiguration/URI/Mongo.URI.Authority.swift
index 9a8941e5..1a2c19fa 100644
--- a/Sources/MongoConfiguration/URI/Mongo.URI.Authority.swift
+++ b/Sources/MongoConfiguration/URI/Mongo.URI.Authority.swift
@@ -1,10 +1,10 @@
-import MongoSchema
+import MongoABI
extension Mongo.URI
{
/// The first two significant components of a connection string URI.
/// It contains login credentials (which may be empty), and a list of
- /// domains. To append a path component to it, use the ``/(self:path:)``
+ /// domains. To append a path component to it, use the ``Authority//(_:_:) [1DYBW]``
/// operator, which returns a ``Location``.
@frozen public
struct Authority