···2222 name: Testing CBOR (ubuntu)
2323 needs: swiftlint
2424 runs-on: ubuntu-latest
2525- container: swift:6.2-noble
2525+ container: swift:6.0-noble
2626 steps:
2727 - name: Checkout repository
2828 uses: actions/checkout@v5
2929+ - uses: swift-actions/setup-swift@next
3030+ with:
3131+ swift-version: "6.0"
2932 - name: Restore .build
3033 id: "restore-build"
3134 uses: actions/cache/restore@v4
···5356 uses: actions/checkout@v5
5457 - uses: swift-actions/setup-swift@next
5558 with:
5656- swift-version: "6.1"
5959+ swift-version: "6.0"
5760 - name: Restore .build
5861 id: "restore-build"
5962 uses: actions/cache/restore@v4
···6265 key: "swiftpm-tests-build-${{ runner.os }}-${{ github.event.pull_request.base.sha || github.event.after }}"
6366 restore-keys: "swiftpm-tests-build-${{ runner.os }}-"
6467 - name: Building Package
6565- run: set -o pipefail && swift build --build-tests | xcbeautify --renderer github-actions
6868+ run: set -o pipefail && swift build --build-tests | xcbeautify
6669# run: set -o pipefail && swift build --build-tests // --sanitize fuzzer | xcbeautify
6770 - name: Cache .build
6871 if: steps.restore-build.outputs.cache-hit != 'true'
···7174 path: .build
7275 key: "swiftpm-tests-build-${{ runner.os }}-${{ github.event.pull_request.base.sha || github.event.after }}"
7376 - name: Testing Package
7474- run: set -o pipefail && swift test --skip-build | xcbeautify --renderer github-actions
7777+ run: set -o pipefail && swift test --skip-build | xcbeautify
7578# TODO: The Xcode version of the swift toolchain does not come with libfuzzer
7679# What needs to happen is we install the open source toolchain and then we can fuzz here...
7780# - name: Fuzzing For 15 Seconds
+13-12
README.md
···3232- Supports decoding half precision floats (Float16) as a regular Float.
3333- Runs on Linux, Android, and Windows using the swift-foundation project when available.
3434- Fuzz tested for reliability against crashes.
3535-- ***NEW*** Supports tagged items with custom tag injection.
3636- - Dates are a special case, handled by the library.
3737- - Contains UUID example implementation.
3535+- Supports tagged items (will expand and add ability to inject your own tags in the future):
3636+ - Dates
3737+ - UUIDs
3838+ - [CIDs](https://github.com/multiformats/cid) (tag 42)
3839- Flexible date parsing (tags `0` or `1` with support for any numeric value representation).
3940- Decoding multiple top-level objects using `decodeMultiple(_:from:)`.
4040-- ***NEW*** IPLD compatible DAG-CBOR encoder for content addressable data.
4141-- ***NEW*** Flexible date decoding for untagged date items encoded as strings, floating point values, or integers.
4141+- *NEW* IPLD compatible DAG-CBOR encoder for content addressable data.
4242+- *NEW* Flexible date decoding for untagged date items encoded as strings, floating point values, or integers.
4343+4444+> Note: This is not a valid CBOR/CDE encoder, it merely always outputs countable collections. CBOR/CDE should be implemented in the future as it's quite similar.
42454346## Usage
4447···8790let dagEncoder = DAGCBOREncoder(dateEncodingStrategy: .double)
8891```
89929090-> [!NOTE]
9191-> DAG-CBOR does not allow tagged items (besides the CID item), and thus encoding dates must be done by encoding their 'raw' value directly. This is an application specific behavior, so ensure the encoder is using the correct date encoding behavior for compatibility. By default, the encoder will encode dates as an epoch `Double` timestamp.
9292-9393-To use with CIDs, conform your internal CID type to ``CIDType``. Do not conform standard types like `String` or `Data` to ``CIDType``, or the encoder may attempt to encode all of those data as tagged items.
9393+To use, conform your internal CID type to ``CIDType``. Do not conform standard types like `String` or `Data` to ``CIDType``, or the encoder will attempt to encode all of those data as tagged items.
9494```swift
9595struct CID: CIDType {
9696 let data: Data
···112112 }
113113}
114114```
115115-116115> [!WARNING]
117116>
118118-> It's *your* responsibility to correctly encode CIDs in the data container. That includes the `NULL` byte for raw binary CID encoding (which DAG-CBOR expects).
117117+> You **need** to prefix your data with the `NULL` byte when encoding. This library will not handle that for you. It is invalid DAG-CBOR encoding to not include the prefixed byte.
119118120119Now, any time the encoder finds a `CID` type it will encode it using the correct tag.
121120```swift
···128127// 4A # bytes(10)
129128// 00000102030405060708 # "\u0000\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b"
130129```
130130+> [!NOTE]
131131+> DAG-CBOR does not allow tagged items (besides the CID item), and thus encoding dates must be done by encoding their 'raw' value directly. This is an application specific behavior, so ensure the encoder is using the correct date encoding behavior for compatibility. By default, the encoder will encode dates as an epoch `Double` timestamp.
131132132133## Documentation
133134···139140140141```swift
141142dependencies: [
142142- .package(url: "https://github.com/thecoolwinter/CBOR.git", from: "1.1.0")
143143+ .package(url: "https://github.com/thecoolwinter/CBOR.git", from: "1.0.0")
143144]
144145```
145146
+51-24
Sources/CBOR/Decoder/CBORDecoder.swift
···2323 public var options: DecodingOptions
24242525 /// Create a new CBOR decoder.
2626- ///
2727- /// All parameters match flags in ``DecodingOptions``.
2828- public init(
2929- rejectIndeterminateLengths: Bool = true,
3030- recursionDepth: Int = 50,
3131- rejectIntKeys: Bool = false,
3232- rejectUnorderedMap: Bool = false,
3333- rejectUndefined: Bool = false,
3434- rejectNaN: Bool = false,
3535- rejectInf: Bool = false,
3636- singleTopLevelItem: Bool = false
3737- ) {
3838- self.options = DecodingOptions(
3939- rejectIndeterminateLengths: rejectIndeterminateLengths,
4040- recursionDepth: recursionDepth,
4141- rejectIntKeys: rejectIntKeys,
4242- rejectUnorderedMap: rejectUnorderedMap,
4343- rejectUndefined: rejectUndefined,
4444- rejectNaN: rejectNaN,
4545- rejectInf: rejectInf,
4646- singleTopLevelItem: singleTopLevelItem
4747- )
2626+ /// - Parameter rejectIndeterminateLengths: Set to `false` to allow indeterminate length objects to be decoded.
2727+ /// Defaults to *rejecting* indeterminate length items (strings, bytes,
2828+ /// maps, and arrays).
2929+ public init(rejectIndeterminateLengths: Bool = true) {
3030+ self.options = DecodingOptions(rejectIndeterminateLengths: rejectIndeterminateLengths)
4831 }
49325033 /// Create a new CBOR decoder
···7861 }
7962 } catch {
8063 if let error = error as? ScanError {
8181- throw error.decodingError()
6464+ try throwScanError(error)
8265 } else {
8366 throw error
8467 }
···128111 }
129112 } catch {
130113 if let error = error as? ScanError {
131131- throw error.decodingError()
114114+ try throwScanError(error)
132115 } else {
133116 throw error
134117 }
118118+ }
119119+ }
120120+121121+ private func throwScanError(_ error: ScanError) throws -> Never {
122122+ switch error {
123123+ case .unexpectedEndOfData:
124124+ throw DecodingError.dataCorrupted(
125125+ .init(codingPath: [], debugDescription: "Unexpected end of data.")
126126+ )
127127+ case let .invalidMajorType(byte, offset):
128128+ throw DecodingError.dataCorrupted(.init(
129129+ codingPath: [],
130130+ debugDescription: "Unexpected major type: \(String(byte, radix: 2)) at offset \(offset)"
131131+ ))
132132+ case let .invalidSize(byte, offset):
133133+ throw DecodingError.dataCorrupted(.init(
134134+ codingPath: [],
135135+ debugDescription: "Unexpected size argument: \(String(byte, radix: 2)) at offset \(offset)"
136136+ ))
137137+ case let .expectedMajorType(offset):
138138+ throw DecodingError.dataCorrupted(.init(
139139+ codingPath: [],
140140+ debugDescription: "Expected major type at offset \(offset)"
141141+ ))
142142+ case let .typeInIndeterminateString(type, offset):
143143+ throw DecodingError.dataCorrupted(.init(
144144+ codingPath: [],
145145+ debugDescription: "Unexpected major type in indeterminate \(type) at offset \(offset)"
146146+ ))
147147+ case let .rejectedIndeterminateLength(type, offset):
148148+ throw DecodingError.dataCorrupted(.init(
149149+ codingPath: [],
150150+ debugDescription: "Rejected indeterminate length type \(type) at offset \(offset)"
151151+ ))
152152+ case let .cannotRepresentInt(max, found, offset):
153153+ throw DecodingError.dataCorrupted(
154154+ .init(
155155+ codingPath: [],
156156+ debugDescription: "Failed to decode integer with maximum \(max), "
157157+ + "found \(found) at \(offset)"
158158+ )
159159+ )
160160+ case .noTagInformation, .invalidMajorTypeForTaggedItem:
161161+ throw error // rethrow these guys
135162 }
136163 }
137164}
···1616 let data: DataRegion
1717}
18181919-// MARK: - Decoder
2020-2119extension SingleValueCBORDecodingContainer: Decoder {
2220 func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key: CodingKey {
2321 try KeyedDecodingContainer(KeyedCBORDecodingContainer(context: context, data: data))
···3331}
34323533extension SingleValueCBORDecodingContainer: SingleValueDecodingContainer {
3636- // MARK: - Nil
3737-3834 func decodeNil() -> Bool {
3935 data.isNil()
4036 }
41374242- // MARK: - Bool
4343-4438 func decode(_: Bool.Type) throws -> Bool {
4539 let argument = try checkType(.simple, arguments: 20, 21, as: Bool.self)
4640 return argument == 21
4741 }
48424949- // MARK: - Floating Points
5050-5151- /// Helper for checking floats against decoding flags.
5252- @inline(__always)
5353- private func checkFloatValidity<T: FloatingPoint>(_ value: T) throws -> T {
5454- if context.options.rejectNaN && value.isNaN {
5555- throw DecodingError.dataCorrupted(context.error("Found NaN \(T.self), configured to reject NaN values."))
5656- }
5757-5858- if context.options.rejectInf && value.isInfinite {
5959- throw DecodingError.dataCorrupted(
6060- context.error("Found \(value) \(T.self), configured to reject Infinite values.")
6161- )
6262- }
6363-6464- return value
6565- }
6666-6743 func decode(_: Float.Type) throws -> Float {
6844 let arg = try checkType(.simple, arguments: 25, 26, as: Float.self)
6945 if arg == 25 {
···7349 context.error("Could not decode half-precision float into Swift Float.")
7450 )
7551 }
7676- return try checkFloatValidity(value)
5252+ return value
7753 }
78547955 let floatRaw = try data.read(as: UInt32.self)
8080- return try checkFloatValidity(Float(bitPattern: floatRaw))
5656+ return Float(bitPattern: floatRaw)
8157 }
82588359 func decode(_: Double.Type) throws -> Double {
8460 try checkType(.simple, arguments: 27, as: Double.self)
8561 let doubleRaw = try data.read(as: UInt64.self).littleEndian
8686- return try checkFloatValidity(Double(bitPattern: doubleRaw))
6262+ return Double(bitPattern: doubleRaw)
8763 }
8888-8989- // MARK: - Integers
90649165 func decode<T: Decodable & FixedWidthInteger>(_: T.Type) throws -> T {
9266 try checkType(.uint, .nint, forType: T.self)
···10377 return value
10478 }
10579106106- @available(macOS 15.0, iOS 18.0, tvOS 18.0, watchOS 11.0, visionOS 2.0, *)
107107- func decode(_ type: Int128.Type) throws -> Int128 {
108108- try checkType(.uint, .nint, forType: Int128.self)
109109- let value = try data.readInt(as: Int128.self)
110110- if data.type == .nint {
111111- return -1 - value
112112- }
113113- return value
114114- }
115115-116116- @available(macOS 15.0, iOS 18.0, tvOS 18.0, watchOS 11.0, visionOS 2.0, *)
117117- func decode(_ type: UInt128.Type) throws -> UInt128 {
118118- try checkType(.uint, .nint, forType: UInt128.self)
119119- let value = try data.readInt(as: UInt128.self)
120120- if data.type == .nint {
121121- throw DecodingError.typeMismatch(
122122- Int.self,
123123- context.error("Found a negative integer while attempting to decode an unsigned int \(UInt128.self).")
124124- )
125125- }
126126- return value
127127- }
128128-129129- // MARK: - String
130130-13180 func decode(_: String.Type) throws -> String {
13281 try checkType(.string, forType: String.self)
13382···179128 }
180129 return string
181130 }
182182-183183- // MARK: - Date
184131185132 // Attempt first to decode a tagged date value, then move on and try decoding any of the following as a date:
186133 // - Int
···243190 }
244191 }
245192246246- // MARK: - Data
247247-248193 private func _decode(_: Data.Type) throws -> Data {
249194 try checkType(.bytes, forType: Data.self)
250195···288233 }
289234 return string
290235 }
291291-292292- // MARK: - Decode
293236294237 func decode<T: Decodable>(_ type: T.Type) throws -> T {
295238 // Unfortunate force unwraps here, but necessary
-49
Sources/CBOR/Decoder/DAGCBORDecoder.swift
···11-//
22-// DAGCBORDecoder.swift
33-// CBOR
44-//
55-// Created by Khan Winter on 10/20/25.
66-//
77-88-#if canImport(FoundationEssentials)
99-import FoundationEssentials
1010-#else
1111-import Foundation
1212-#endif
1313-1414-/// Decodes ``Decodable`` objects from DAG-CBOR data.
1515-///
1616-/// This is really just a wrapper for ``CBORDecoder``, which constant configuration flags that ensure valid DAG-CBOR
1717-/// data is decoded.
1818-///
1919-/// If this decoder is too strict, I'd suggest using ``CBORDecoder``, which will be much more flexible around decoding
2020-/// than this type. You can also loosen specific flags using the options member of that struct. For instance, this
2121-/// type will reject all unordered maps. If you find yourself needing to receive badly-defined DAG-CBOR, just
2222-/// use ``CBORDecoder``.
2323-public struct DAGCBORDecoder {
2424- /// The options that determine decoding behavior.
2525- let options: DecodingOptions
2626-2727- /// Create a new DAG-CBOR decoder.
2828- public init() {
2929- self.options = DecodingOptions(
3030- rejectIndeterminateLengths: true,
3131- rejectIntKeys: true,
3232- rejectUnorderedMap: true,
3333- rejectUndefined: true,
3434- rejectNaN: true,
3535- rejectInf: true,
3636- singleTopLevelItem: true
3737- )
3838- }
3939-4040- /// Decodes the given type from DAG-CBOR binary data.
4141- /// - Parameters:
4242- /// - type: The decodable type to deserialize.
4343- /// - data: The DAG-CBOR data to decode from.
4444- /// - Returns: An instance of the decoded type.
4545- /// - Throws: A ``DecodingError`` with context and a debug description for a failed deserialization operation.
4646- public func decode<T: Decodable>(_ type: T.Type, from data: Data) throws -> T {
4747- try CBORDecoder(options: options).decode(T.self, from: data)
4848- }
4949-}
+1-40
Sources/CBOR/Decoder/DecodingOptions.swift
···1313 /// For deterministic encoding, this **must** be enabled.
1414 public var rejectIndeterminateLengths: Bool
15151616- /// Maximum recursion depth.
1717- public var recursionDepth: Int = 50
1818-1919- /// Reject maps with non-string keys..
2020- public var rejectIntKeys: Bool
2121-2222- /// Reject maps whose keys are out of order.
2323- public var rejectUnorderedMap: Bool
2424-2525- /// Reject the `undefined` simple value (`23`).
2626- public var rejectUndefined: Bool
2727-2828- /// Enable to reject decoded `NaN` floating point values.
2929- public var rejectNaN: Bool
3030-3131- /// Enable to reject decoded infinite floating point values.
3232- public var rejectInf: Bool
3333-3434- /// Require that CBOR data encapsulates the *entire* data object being decoded.
3535- /// When true, throws a decoding error if data is left over after scanning for valid CBOR structure, or if there
3636- /// are multiple top-level objects.
3737- public var singleTopLevelItem: Bool
3838-3916 /// Create a new options object.
4040- public init(
4141- rejectIndeterminateLengths: Bool = true,
4242- recursionDepth: Int = 50,
4343- rejectIntKeys: Bool = false,
4444- rejectUnorderedMap: Bool = false,
4545- rejectUndefined: Bool = false,
4646- rejectNaN: Bool = false,
4747- rejectInf: Bool = false,
4848- singleTopLevelItem: Bool = false
4949- ) {
1717+ public init(rejectIndeterminateLengths: Bool = true) {
5018 self.rejectIndeterminateLengths = rejectIndeterminateLengths
5151- self.recursionDepth = recursionDepth
5252- self.rejectIntKeys = rejectIntKeys
5353- self.rejectUnorderedMap = rejectUnorderedMap
5454- self.rejectUndefined = rejectUndefined
5555- self.rejectNaN = rejectNaN
5656- self.rejectInf = rejectInf
5757- self.singleTopLevelItem = singleTopLevelItem
5819 }
5920}
+29-33
Sources/CBOR/Decoder/Scanner/CBORScanner.swift
···1111import Foundation
1212#endif
13131414+@usableFromInline
1515+enum ScanError: Error {
1616+ case unexpectedEndOfData
1717+ case invalidMajorType(byte: UInt8, offset: Int)
1818+ case invalidSize(byte: UInt8, offset: Int)
1919+ case expectedMajorType(offset: Int)
2020+ case typeInIndeterminateString(type: MajorType, offset: Int)
2121+ case rejectedIndeterminateLength(type: MajorType, offset: Int)
2222+ case cannotRepresentInt(max: UInt, found: UInt, offset: Int)
2323+ case noTagInformation(tag: UInt, offset: Int)
2424+ case invalidMajorTypeForTaggedItem(tag: UInt, expected: Set<MajorType>, found: MajorType, offset: Int)
2525+}
2626+1427/// # Why Scan?
1528/// I'd have loved to use a 'pop' method for decoding, where we only decode as data is requested. However, the way
1629/// Swift's decoding APIs work forces us to be able to be able to do random access for keys in maps, which requires
···39524053 consuming func scan() throws -> Results {
4154 while !reader.isEmpty {
4242- if options.singleTopLevelItem && reader.index > 0 {
4343- throw ScanError.unreadDataAfterEnd
4444- }
4545-4655 let idx = reader.index
4747- try scanNext(depth: 0)
5656+ try scanNext()
4857 assert(idx < reader.index, "Scanner made no forward progress in scan")
4958 }
5050-5151- if options.singleTopLevelItem && !reader.isEmpty {
5252- throw ScanError.unreadDataAfterEnd
5353- }
5454-5559 return results
5660 }
57615858- private mutating func scanNext(depth: Int) throws {
6262+ private mutating func scanNext() throws {
5963 guard let type = reader.peekType(), let raw = reader.peek() else {
6064 if reader.isEmpty {
6165 throw ScanError.unexpectedEndOfData
···6468 }
6569 }
66706767- guard depth < options.recursionDepth else {
6868- throw ScanError.recursionLimit
6969- }
7070-7171- try scanType(type: type, raw: raw, depth: depth)
7171+ try scanType(type: type, raw: raw)
7272 }
73737474- private mutating func scanType(type: MajorType, raw: UInt8, depth: Int) throws {
7474+ private mutating func scanType(type: MajorType, raw: UInt8) throws {
7575 switch type {
7676 case .uint, .nint:
7777 try scanInt(raw: raw)
···8080 case .string:
8181 try scanBytesOrString(.string, raw: raw)
8282 case .array:
8383- try scanArray(depth: depth)
8383+ try scanArray()
8484 case .map:
8585- try scanMap(depth: depth)
8585+ try scanMap()
8686 case .simple:
8787 try scanSimple(raw: raw)
8888 case .tagged:
8989- try scanTagged(raw: raw, depth: depth)
8989+ try scanTagged(raw: raw)
9090 }
9191 }
9292···103103 // MARK: - Scan Simple
104104105105 private mutating func scanSimple(raw: UInt8) throws {
106106- guard !(options.rejectUndefined && reader.peekArgument() == 23) else {
107107- throw ScanError.rejectedUndefined
108108- }
109109-110106 let idx = reader.index
111107 results.recordSimple(reader.pop(), currentByteIndex: idx)
112108 guard reader.canRead(raw.simpleLength()) else {
···154150155151 // MARK: - Scan Array
156152157157- private mutating func scanArray(depth: Int) throws {
153153+ private mutating func scanArray() throws {
158154 guard peekIsIndeterminate() else {
159155 let size = try reader.readNextInt(as: Int.self)
160156 let mapIdx = results.recordArrayStart(currentByteIndex: reader.index)
161157 for _ in 0..<size {
162162- try scanNext(depth: depth + 1)
158158+ try scanNext()
163159 }
164160 results.recordEnd(childCount: size, resultLocation: mapIdx, currentByteIndex: reader.index)
165161 return
···173169 reader.pop() // Pop type
174170 var count = 0
175171 while reader.peek() != Constants.breakCode {
176176- try scanNext(depth: depth + 1)
172172+ try scanNext()
177173 count += 1
178174 }
179175 // Pop the break byte
···183179184180 // MARK: - Scan Map
185181186186- private mutating func scanMap(depth: Int) throws {
182182+ private mutating func scanMap() throws {
187183 guard peekIsIndeterminate() else {
188184 let keyCount = try reader.readNextInt(as: Int.self)
189185 guard keyCount < Int.max / 2 else {
···193189 let size = keyCount * 2
194190 let mapIdx = results.recordMapStart(currentByteIndex: reader.index)
195191 for _ in 0..<size {
196196- try scanNext(depth: depth + 1)
192192+ try scanNext()
197193 }
198194 results.recordEnd(childCount: size, resultLocation: mapIdx, currentByteIndex: reader.index)
199195 return
···207203 reader.pop() // Pop type
208204 var count = 0
209205 while reader.peek() != Constants.breakCode {
210210- try scanNext(depth: depth + 1) // Maps should always have a multiple of two values.
211211- try scanNext(depth: depth + 1)
206206+ try scanNext() // Maps should always have a multiple of two values.
207207+ try scanNext()
212208 count += 2
213209 }
214210 // Pop the break byte
···218214219215 // MARK: - Scan Tagged
220216221221- private mutating func scanTagged(raw: UInt8, depth: Int) throws {
217217+ private mutating func scanTagged(raw: UInt8) throws {
222218 // Scan the tag number (passing the raw value here makes it record a Tag rather than an Int)
223219 try scanInt(raw: raw)
224220···226222 throw ScanError.unexpectedEndOfData
227223 }
228224229229- try scanType(type: nextTag, raw: nextRaw, depth: depth)
225225+ try scanType(type: nextTag, raw: nextRaw)
230226 }
231227}
232228
-103
Sources/CBOR/Decoder/Scanner/ScanError.swift
···11-//
22-// ScanError.swift
33-// CBOR
44-//
55-// Created by Khan Winter on 10/21/25.
66-//
77-88-@usableFromInline
99-enum ScanError: Error {
1010- case unexpectedEndOfData
1111- case invalidMajorType(byte: UInt8, offset: Int)
1212- case invalidSize(byte: UInt8, offset: Int)
1313- case expectedMajorType(offset: Int)
1414- case typeInIndeterminateString(type: MajorType, offset: Int)
1515- case rejectedIndeterminateLength(type: MajorType, offset: Int)
1616- case cannotRepresentInt(max: UInt, found: UInt, offset: Int)
1717- case recursionLimit
1818- case unreadDataAfterEnd
1919- case rejectedUndefined
2020- case unnecessaryInt
2121-2222- // swiftlint:disable:next cyclomatic_complexity function_body_length
2323- func decodingError() -> DecodingError {
2424- switch self {
2525- case .unexpectedEndOfData:
2626- return DecodingError.dataCorrupted(
2727- .init(codingPath: [], debugDescription: "Unexpected end of data.", underlyingError: self)
2828- )
2929- case let .invalidMajorType(byte, offset):
3030- return DecodingError.dataCorrupted(.init(
3131- codingPath: [],
3232- debugDescription: "Unexpected major type: \(String(byte, radix: 2)) at offset \(offset)",
3333- underlyingError: self
3434- ))
3535- case let .invalidSize(byte, offset):
3636- return DecodingError.dataCorrupted(.init(
3737- codingPath: [],
3838- debugDescription: "Unexpected size argument: \(String(byte, radix: 2)) at offset \(offset)",
3939- underlyingError: self
4040- ))
4141- case let .expectedMajorType(offset):
4242- return DecodingError.dataCorrupted(.init(
4343- codingPath: [],
4444- debugDescription: "Expected major type at offset \(offset)",
4545- underlyingError: self
4646- ))
4747- case let .typeInIndeterminateString(type, offset):
4848- return DecodingError.dataCorrupted(.init(
4949- codingPath: [],
5050- debugDescription: "Unexpected major type in indeterminate \(type) at offset \(offset)",
5151- underlyingError: self
5252- ))
5353- case let .rejectedIndeterminateLength(type, offset):
5454- return DecodingError.dataCorrupted(.init(
5555- codingPath: [],
5656- debugDescription: "Rejected indeterminate length type \(type) at offset \(offset)",
5757- underlyingError: self
5858- ))
5959- case let .cannotRepresentInt(max, found, offset):
6060- return DecodingError.dataCorrupted(
6161- .init(
6262- codingPath: [],
6363- debugDescription: "Failed to decode integer with maximum \(max), "
6464- + "found \(found) at \(offset)",
6565- underlyingError: self
6666- )
6767- )
6868- case .recursionLimit:
6969- return DecodingError.dataCorrupted(
7070- .init(
7171- codingPath: [],
7272- debugDescription: "Recursion depth limit exceeded (DecodingOptions.recursionDepth)",
7373- underlyingError: self
7474- )
7575- )
7676- case .unreadDataAfterEnd:
7777- return DecodingError.dataCorrupted(
7878- .init(
7979- codingPath: [],
8080- debugDescription: "Configured to reject CBOR data with trailing bytes (DecodingOptions."
8181- + "singleTopLevelItem)",
8282- underlyingError: self
8383- )
8484- )
8585- case .rejectedUndefined:
8686- return DecodingError.dataCorrupted(
8787- .init(
8888- codingPath: [],
8989- debugDescription: "Configured to reject undefined values (DecodingOptions.rejectUndefined)",
9090- underlyingError: self
9191- )
9292- )
9393- case .unnecessaryInt:
9494- return DecodingError.dataCorrupted(
9595- .init(
9696- codingPath: [],
9797- debugDescription: "Found integer that was encoded in a larger data format than necessary",
9898- underlyingError: self
9999- )
100100- )
101101- }
102102- }
103103-}
+1-1
Sources/CBOR/Encoder/CBOREncoder.swift
···5656 let tempStorage = TopLevelTemporaryEncodingStorage()
57575858 let encodingContext = EncodingContext(options: options)
5959- let encoder = try SingleValueCBOREncodingContainer(parent: tempStorage, context: encodingContext)
5959+ let encoder = SingleValueCBOREncodingContainer(parent: tempStorage, context: encodingContext)
6060 try encoder.encode(value)
61616262 let dataSize = tempStorage.value.size
···11-// From https://github.com/Flight-School/AnyCodable/blob/master/Sources/AnyCodable/AnyDecodable.swift
22-33-// swiftlint:disable cyclomatic_complexity
44-// swiftlint:disable line_length
55-// swiftlint:disable type_name
66-77-#if canImport(FoundationEssentials)
88-import FoundationEssentials
99-#else
1010-import Foundation
1111-#endif
1212-1313-/**
1414- A type-erased `Decodable` value.
1515-1616- The `AnyDecodable` type forwards decoding responsibilities
1717- to an underlying value, hiding its specific underlying type.
1818-1919- You can decode mixed-type values in dictionaries
2020- and other collections that require `Decodable` conformance
2121- by declaring their contained type to be `AnyDecodable`:
2222-2323- let json = """
2424- {
2525- "boolean": true,
2626- "integer": 42,
2727- "double": 3.141592653589793,
2828- "string": "string",
2929- "array": [1, 2, 3],
3030- "nested": {
3131- "a": "alpha",
3232- "b": "bravo",
3333- "c": "charlie"
3434- },
3535- "null": null
3636- }
3737- """.data(using: .utf8)!
3838-3939- let decoder = JSONDecoder()
4040- let dictionary = try! decoder.decode([String: AnyDecodable].self, from: json)
4141- */
4242-struct AnyDecodable: Decodable {
4343- let value: Any
4444-4545- init<T>(_ value: T?) {
4646- self.value = value ?? ()
4747- }
4848-}
4949-5050-@usableFromInline
5151-protocol _AnyDecodable {
5252- var value: Any { get }
5353- init<T>(_ value: T?)
5454-}
5555-5656-extension AnyDecodable: _AnyDecodable {}
5757-5858-extension _AnyDecodable {
5959- init(from decoder: Decoder) throws {
6060- let container = try decoder.singleValueContainer()
6161-6262- if container.decodeNil() {
6363- self.init(Optional<Self>.none)
6464- } else if let bool = try? container.decode(Bool.self) {
6565- self.init(bool)
6666- } else if let int = try? container.decode(Int.self) {
6767- self.init(int)
6868- } else if let uint = try? container.decode(UInt.self) {
6969- self.init(uint)
7070- } else if let double = try? container.decode(Double.self) {
7171- self.init(double)
7272- } else if let string = try? container.decode(String.self) {
7373- self.init(string)
7474- } else if let array = try? container.decode([AnyDecodable].self) {
7575- self.init(array.map { $0.value })
7676- } else if let dictionary = try? container.decode([String: AnyDecodable].self) {
7777- self.init(dictionary.mapValues { $0.value })
7878- } else {
7979- throw DecodingError.dataCorruptedError(in: container, debugDescription: "AnyDecodable value cannot be decoded")
8080- }
8181- }
8282-}
8383-8484-extension AnyDecodable: Equatable {
8585- static func == (lhs: AnyDecodable, rhs: AnyDecodable) -> Bool {
8686- switch (lhs.value, rhs.value) {
8787- case (Optional<Self>.none, Optional<Self>.none), is (Void, Void):
8888- return true
8989- case let (lhs as Bool, rhs as Bool):
9090- return lhs == rhs
9191- case let (lhs as Int, rhs as Int):
9292- return lhs == rhs
9393- case let (lhs as Int8, rhs as Int8):
9494- return lhs == rhs
9595- case let (lhs as Int16, rhs as Int16):
9696- return lhs == rhs
9797- case let (lhs as Int32, rhs as Int32):
9898- return lhs == rhs
9999- case let (lhs as Int64, rhs as Int64):
100100- return lhs == rhs
101101- case let (lhs as UInt, rhs as UInt):
102102- return lhs == rhs
103103- case let (lhs as UInt8, rhs as UInt8):
104104- return lhs == rhs
105105- case let (lhs as UInt16, rhs as UInt16):
106106- return lhs == rhs
107107- case let (lhs as UInt32, rhs as UInt32):
108108- return lhs == rhs
109109- case let (lhs as UInt64, rhs as UInt64):
110110- return lhs == rhs
111111- case let (lhs as Float, rhs as Float):
112112- return lhs == rhs
113113- case let (lhs as Double, rhs as Double):
114114- return lhs == rhs
115115- case let (lhs as String, rhs as String):
116116- return lhs == rhs
117117- case let (lhs as [String: AnyDecodable], rhs as [String: AnyDecodable]):
118118- return lhs == rhs
119119- case let (lhs as [AnyDecodable], rhs as [AnyDecodable]):
120120- return lhs == rhs
121121- default:
122122- return false
123123- }
124124- }
125125-}
126126-127127-extension AnyDecodable: CustomStringConvertible {
128128- var description: String {
129129- switch value {
130130- case is Void:
131131- return String(describing: nil as Any?)
132132- case let value as CustomStringConvertible:
133133- return value.description
134134- default:
135135- return String(describing: value)
136136- }
137137- }
138138-}
139139-140140-extension AnyDecodable: CustomDebugStringConvertible {
141141- var debugDescription: String {
142142- switch value {
143143- case let value as CustomDebugStringConvertible:
144144- return "AnyDecodable(\(value.debugDescription))"
145145- default:
146146- return "AnyDecodable(\(description))"
147147- }
148148- }
149149-}
150150-151151-extension AnyDecodable: Hashable {
152152- func hash(into hasher: inout Hasher) {
153153- switch value {
154154- case let value as Bool:
155155- hasher.combine(value)
156156- case let value as Int:
157157- hasher.combine(value)
158158- case let value as Int8:
159159- hasher.combine(value)
160160- case let value as Int16:
161161- hasher.combine(value)
162162- case let value as Int32:
163163- hasher.combine(value)
164164- case let value as Int64:
165165- hasher.combine(value)
166166- case let value as UInt:
167167- hasher.combine(value)
168168- case let value as UInt8:
169169- hasher.combine(value)
170170- case let value as UInt16:
171171- hasher.combine(value)
172172- case let value as UInt32:
173173- hasher.combine(value)
174174- case let value as UInt64:
175175- hasher.combine(value)
176176- case let value as Float:
177177- hasher.combine(value)
178178- case let value as Double:
179179- hasher.combine(value)
180180- case let value as String:
181181- hasher.combine(value)
182182- case let value as [String: AnyDecodable]:
183183- hasher.combine(value)
184184- case let value as [AnyDecodable]:
185185- hasher.combine(value)
186186- default:
187187- break
188188- }
189189- }
190190-}
191191-192192-// swiftlint:enable cyclomatic_complexity
193193-// swiftlint:enable line_length
194194-// swiftlint:enable type_name