From 35ac5572dd131a07a0372b80849aa78462be83ea Mon Sep 17 00:00:00 2001 From: Christoph Hagen Date: Sat, 21 Jan 2023 09:54:03 +0100 Subject: [PATCH 01/10] Remove dependency on Half, use Float16 instead --- Package.swift | 10 ++++------ Sources/CBORCoding/CBORDecoder.swift | 2 ++ Sources/CBORCoding/CBOREncoder.swift | 2 ++ Sources/CBORCoding/CBORParser.swift | 1 - Sources/CBORCoding/Half.swift | 5 +++++ Tests/CBORCodingTests/CBORDecoderTests.swift | 2 ++ Tests/CBORCodingTests/CBOREncoderTests.swift | 2 ++ Tests/CBORCodingTests/CBORParserTests.swift | 2 ++ 8 files changed, 19 insertions(+), 7 deletions(-) create mode 100644 Sources/CBORCoding/Half.swift diff --git a/Package.swift b/Package.swift index b77b5ec..675c051 100644 --- a/Package.swift +++ b/Package.swift @@ -6,7 +6,7 @@ let package = Package( platforms: [ .iOS("9.0"), - .macOS("10.10"), + .macOS(.v11), .tvOS("9.0"), .watchOS("2.0") ], @@ -15,13 +15,11 @@ let package = Package( .library(name: "CBORCoding", targets: ["CBORCoding"]) ], - dependencies: [ - .package(url: "https://github.com/SomeRandomiOSDev/Half", from: "1.3.1") - ], + dependencies: [], targets: [ - .target(name: "CBORCoding", dependencies: ["Half"]), - .testTarget(name: "CBORCodingTests", dependencies: ["CBORCoding", "Half"]) + .target(name: "CBORCoding", dependencies: []), + .testTarget(name: "CBORCodingTests", dependencies: ["CBORCoding"]) ], swiftLanguageVersions: [.version("4.2"), .version("5")] diff --git a/Sources/CBORCoding/CBORDecoder.swift b/Sources/CBORCoding/CBORDecoder.swift index 9343c31..59d4cab 100644 --- a/Sources/CBORCoding/CBORDecoder.swift +++ b/Sources/CBORCoding/CBORDecoder.swift @@ -6,7 +6,9 @@ // import Foundation +#if canImport(Half) import Half +#endif #if canImport(Combine) import Combine diff --git a/Sources/CBORCoding/CBOREncoder.swift b/Sources/CBORCoding/CBOREncoder.swift index d89c08a..9de89ad 100644 --- a/Sources/CBORCoding/CBOREncoder.swift +++ b/Sources/CBORCoding/CBOREncoder.swift @@ -6,7 +6,9 @@ // import Foundation +#if canImport(Half) import Half +#endif #if canImport(Combine) import Combine diff --git a/Sources/CBORCoding/CBORParser.swift b/Sources/CBORCoding/CBORParser.swift index 0566522..5383ff4 100644 --- a/Sources/CBORCoding/CBORParser.swift +++ b/Sources/CBORCoding/CBORParser.swift @@ -6,7 +6,6 @@ // import Foundation -import Half // MARK: - CBORParser Definition diff --git a/Sources/CBORCoding/Half.swift b/Sources/CBORCoding/Half.swift new file mode 100644 index 0000000..60cd4f7 --- /dev/null +++ b/Sources/CBORCoding/Half.swift @@ -0,0 +1,5 @@ +import Foundation + +#if !canImport(Half) +typealias Half = Float16 +#endif diff --git a/Tests/CBORCodingTests/CBORDecoderTests.swift b/Tests/CBORCodingTests/CBORDecoderTests.swift index 0976f41..45488b6 100644 --- a/Tests/CBORCodingTests/CBORDecoderTests.swift +++ b/Tests/CBORCodingTests/CBORDecoderTests.swift @@ -8,7 +8,9 @@ // swiftlint:disable nesting function_body_length force_cast identifier_name opening_brace comma implicitly_unwrapped_optional number_separator force_unwrapping @testable import CBORCoding +#if canImport(Half) import Half +#endif import XCTest // MARK: - CBORDecoderTests Definition diff --git a/Tests/CBORCodingTests/CBOREncoderTests.swift b/Tests/CBORCodingTests/CBOREncoderTests.swift index b85a428..5d04f93 100644 --- a/Tests/CBORCodingTests/CBOREncoderTests.swift +++ b/Tests/CBORCodingTests/CBOREncoderTests.swift @@ -8,7 +8,9 @@ // swiftlint:disable comma nesting function_body_length identifier_name force_try force_cast number_separator force_unwrapping @testable import CBORCoding +#if canImport(Half) import Half +#endif import XCTest // MARK: - CBORTests Definition diff --git a/Tests/CBORCodingTests/CBORParserTests.swift b/Tests/CBORCodingTests/CBORParserTests.swift index d77d272..5860f1b 100644 --- a/Tests/CBORCodingTests/CBORParserTests.swift +++ b/Tests/CBORCodingTests/CBORParserTests.swift @@ -8,7 +8,9 @@ // swiftlint:disable function_body_length force_cast comma force_try implicitly_unwrapped_optional number_separator force_unwrapping @testable import CBORCoding +#if canImport(Half) import Half +#endif import XCTest // MARK: - CBORParserTests Definition From 4ea7604d131cacbbf514cbbf6d7eda6ee89c1c6b Mon Sep 17 00:00:00 2001 From: Christoph Hagen Date: Sun, 29 Jan 2023 10:35:55 +0100 Subject: [PATCH 02/10] Replace Half with Float16 and fix linting warnings --- Package.swift | 9 +- Sources/CBORCoding/CBOR.swift | 3 +- Sources/CBORCoding/CBORDecoder.swift | 112 ++++++++----------- Sources/CBORCoding/CBOREncoder.swift | 102 ++++++++--------- Sources/CBORCoding/CBORParser.swift | 10 +- Sources/CBORCoding/Half.swift | 6 +- Tests/CBORCodingTests/CBORDecoderTests.swift | 67 ++++++----- Tests/CBORCodingTests/CBOREncoderTests.swift | 25 ++--- Tests/CBORCodingTests/CBORParserTests.swift | 49 ++++---- 9 files changed, 181 insertions(+), 202 deletions(-) diff --git a/Package.swift b/Package.swift index 675c051..91ec4ea 100644 --- a/Package.swift +++ b/Package.swift @@ -5,10 +5,11 @@ let package = Package( name: "CBORCoding", platforms: [ - .iOS("9.0"), + .iOS(.v14), .macOS(.v11), - .tvOS("9.0"), - .watchOS("2.0") + .tvOS(.v14), + .watchOS(.v7), + .macCatalyst(.v14), ], products: [ @@ -22,5 +23,5 @@ let package = Package( .testTarget(name: "CBORCodingTests", dependencies: ["CBORCoding"]) ], - swiftLanguageVersions: [.version("4.2"), .version("5")] + swiftLanguageVersions: [.v5] ) diff --git a/Sources/CBORCoding/CBOR.swift b/Sources/CBORCoding/CBOR.swift index 8a19f37..04e4a11 100644 --- a/Sources/CBORCoding/CBOR.swift +++ b/Sources/CBORCoding/CBOR.swift @@ -321,7 +321,8 @@ public enum CBOR { /// The string composed by joining together all of the data chunks and interpreting /// it as a UTF8 encoded string. - @inline(__always) public var stringValue: String? { + @inline(__always) + public var stringValue: String? { return stringValue(as: .utf8) } diff --git a/Sources/CBORCoding/CBORDecoder.swift b/Sources/CBORCoding/CBORDecoder.swift index 59d4cab..f1daa46 100644 --- a/Sources/CBORCoding/CBORDecoder.swift +++ b/Sources/CBORCoding/CBORDecoder.swift @@ -6,9 +6,6 @@ // import Foundation -#if canImport(Half) -import Half -#endif #if canImport(Combine) import Combine @@ -288,34 +285,34 @@ internal class __CBORDecoder: Decoder, SingleValueDecodingContainer { } fileprivate func decode(_ value: Any, as type: T.Type) throws -> T { - let result: T - // swiftlint:disable force_cast if type == Data.self, let value = value as? CBORDecodedData { - result = value.decodedDataValue() as! T - } else if type == String.self, let value = value as? CBORDecodedString { - result = try value.decodedStringValue() as! T - } else if type == CBOR.NegativeUInt64.self { - result = try decode(value, as: CBOR.NegativeUInt64.self) as! T - } else if type == CBOR.Undefined.self { + return value.decodedDataValue() as! T + } + if type == String.self, let value = value as? CBORDecodedString { + return try value.decodedStringValue() as! T + } + if type == CBOR.NegativeUInt64.self { + return try decode(value, as: CBOR.NegativeUInt64.self) as! T + } + if type == CBOR.Undefined.self { guard let decodedValue = value as? T else { throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } - result = decodedValue - } else if let decodedValue = value as? T { - result = decodedValue - } else if type == Half.self { - result = try decodeFloatingPoint(value, as: Half.self) as! T - } else { - storage.push(container: value) - defer { storage.popContainer() } - - result = try type.init(from: self) + return decodedValue + } + if let decodedValue = value as? T { + return decodedValue + } + if type == Float16.self { + return try decodeFloatingPoint(value, as: Float16.self) as! T } - // swiftlint:enable force_cast - return result + storage.push(container: value) + defer { storage.popContainer() } + // swiftlint:enable force_cast + return try type.init(from: self) } // @@ -380,54 +377,39 @@ internal class __CBORDecoder: Decoder, SingleValueDecodingContainer { } fileprivate func decodeFloatingPoint(_ value: Any, as type: T.Type) throws -> T where T: BinaryFloatingPoint { - let floatingPoint: T - if let half = value as? Half { - if half.isNaN { - if half.isSignalingNaN { - floatingPoint = .signalingNaN - } else { - floatingPoint = .nan - } - } else { - guard let value = T(exactly: half) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Decoded CBOR number <\(half)> does not fit in \(type).")) - } - - floatingPoint = value + if let half = value as? Float16 { + guard !half.isNaN else { + return half.isSignalingNaN ? .signalingNaN : .nan } - } else if let float = value as? Float { - if float.isNaN { - if float.isSignalingNaN { - floatingPoint = .signalingNaN - } else { - floatingPoint = .nan - } - } else { - guard let value = T(exactly: float) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Decoded CBOR number <\(float)> does not fit in \(type).")) - } - - floatingPoint = value + guard let value = T(exactly: half) else { + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Decoded CBOR number <\(half)> does not fit in \(type).")) } - } else if let double = value as? Double { - if double.isNaN { - if double.isSignalingNaN { - floatingPoint = .signalingNaN - } else { - floatingPoint = .nan - } - } else { - guard let value = T(exactly: double) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Decoded CBOR number <\(double)> does not fit in \(type).")) - } - floatingPoint = value + return value + } + + if let float = value as? Float { + guard !float.isNaN else { + return float.isSignalingNaN ? .signalingNaN : .nan } - } else { - throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) + guard let value = T(exactly: float) else { + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Decoded CBOR number <\(float)> does not fit in \(type).")) + } + + return value } + if let double = value as? Double { + guard !double.isNaN else { + return double.isSignalingNaN ? .signalingNaN : .nan + } + guard let value = T(exactly: double) else { + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Decoded CBOR number <\(double)> does not fit in \(type).")) + } - return floatingPoint + return value + + } + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } fileprivate func decode(_ value: Any, as type: CBOR.NegativeUInt64.Type) throws -> CBOR.NegativeUInt64 { diff --git a/Sources/CBORCoding/CBOREncoder.swift b/Sources/CBORCoding/CBOREncoder.swift index 9de89ad..72808cf 100644 --- a/Sources/CBORCoding/CBOREncoder.swift +++ b/Sources/CBORCoding/CBOREncoder.swift @@ -6,9 +6,6 @@ // import Foundation -#if canImport(Half) -import Half -#endif #if canImport(Combine) import Combine @@ -229,7 +226,7 @@ open class CBOREncoder { return Data(bytes) } - internal static func encode(_ value: Half) -> Data { + internal static func encode(_ value: Float16) -> Data { var half = value let data = Data(bytes: &half, count: MemoryLayout.size(ofValue: half)) @@ -714,60 +711,65 @@ internal class __CBOREncoder: CBOREncoderProtocol, SingleValueEncodingContainer } fileprivate func encodeValueToCBOR(_ value: Encodable) throws -> Any? { - let result: Any? - if let encoded = value as? CBOR.CBOREncoded { - result = encoded.encodedData - } else if let date = value as? Date { - result = CBOREncoder.encode(date, using: options.dateEncodingStrategy) - } else if let data = value as? Data { - result = CBOREncoder.encode(data) - } else if let url = value as? URL { + return encoded.encodedData + } + if let date = value as? Date { + return CBOREncoder.encode(date, using: options.dateEncodingStrategy) + } + if let data = value as? Data { + return CBOREncoder.encode(data) + } + if let url = value as? URL { // swiftlint:disable force_try - result = try! CBOREncoder.encode(url, forTag: .uri).encodedData + return try! CBOREncoder.encode(url, forTag: .uri).encodedData // swiftlint:enable force_try - } else if value is NSNull || value is CBOR.Null { - result = CBOREncoder.encodeNil() - } else if value is CBOR.Undefined { - result = CBOREncoder.encodeUndefined() - } else if let dict = value as? [String: Encodable] { - result = try encode(dict) - } else if let dict = value as? [Int: Encodable] { - result = try encode(dict) - } else if let data = value as? CBOR.IndefiniteLengthData { - result = try encode(data) - } else if let string = value as? CBOR.IndefiniteLengthString { - result = try encode(string) - } else if let value = value as? CBOR.NegativeUInt64 { - result = CBOREncoder.encode(value) - } else if let value = value as? Half { - result = CBOREncoder.encode(value) - } else { - let action: () throws -> Any? = { - let depth = self.storage.count - - do { - try value.encode(to: self) - } catch { - if self.storage.count > depth { - _ = self.storage.popContainer() - } - - throw error + } + if value is NSNull || value is CBOR.Null { + return CBOREncoder.encodeNil() + } + if value is CBOR.Undefined { + return CBOREncoder.encodeUndefined() + } + if let dict = value as? [String: Encodable] { + return try encode(dict) + } + if let dict = value as? [Int: Encodable] { + return try encode(dict) + } + if let data = value as? CBOR.IndefiniteLengthData { + return try encode(data) + } + if let string = value as? CBOR.IndefiniteLengthString { + return try encode(string) + } + if let value = value as? CBOR.NegativeUInt64 { + return CBOREncoder.encode(value) + } + if let value = value as? Float16 { + return CBOREncoder.encode(value) + } + let action: () throws -> Any? = { + let depth = self.storage.count + + do { + try value.encode(to: self) + } catch { + if self.storage.count > depth { + _ = self.storage.popContainer() } - - guard self.storage.count > depth else { return nil } - return self.storage.popContainer() + throw error } - if newContainerLength.contains(.includeSubcontainers) { - result = try action() - } else { - result = try definiteLengthContainerContext(action) - } + guard self.storage.count > depth else { return nil } + return self.storage.popContainer() } - return result + if newContainerLength.contains(.includeSubcontainers) { + return try action() + } else { + return try definiteLengthContainerContext(action) + } } // MARK: Encoder Protocol Requirements diff --git a/Sources/CBORCoding/CBORParser.swift b/Sources/CBORCoding/CBORParser.swift index 5383ff4..55457db 100644 --- a/Sources/CBORCoding/CBORParser.swift +++ b/Sources/CBORCoding/CBORParser.swift @@ -225,7 +225,7 @@ internal class CBORParser { index += simple.decodedBytes case 25: - let half = try decode(Half.self, from: data[index...]) + let half = try decode(Float16.self, from: data[index...]) try storage.append(half.value) index += half.decodedBytes @@ -626,10 +626,10 @@ internal class CBORParser { } let result: (value: T, decodedBytes: Int) - if header == CBOR.Bits.half.rawValue { // Half + if header == CBOR.Bits.half.rawValue { // Float16 if data.count >= 3 { // swiftlint:disable force_unwrapping - let half = data[data.index(data.startIndex, offsetBy: 1) ..< data.index(data.startIndex, offsetBy: 3)].reversed().withUnsafeBytes { $0.bindMemory(to: Half.self).baseAddress!.pointee } + let half = data[data.index(data.startIndex, offsetBy: 1) ..< data.index(data.startIndex, offsetBy: 3)].reversed().withUnsafeBytes { $0.bindMemory(to: Float16.self).baseAddress!.pointee } // swiftlint:enable force_unwrapping if half.isNaN { @@ -725,7 +725,7 @@ internal class CBORParser { if data.count >= 5 { let upper = UInt32(data[data.index(data.startIndex, offsetBy: 1)]) << 24 | UInt32(data[data.index(data.startIndex, offsetBy: 2)]) << 16 - let lower = UInt32(data[data.index(data.startIndex, offsetBy: 3)]) << 8 | + let lower = UInt32(data[data.index(data.startIndex, offsetBy: 3)]) << 8 | UInt32(data[data.index(data.startIndex, offsetBy: 4)]) result = (T(exactly: upper | lower), 5) @@ -746,7 +746,7 @@ internal class CBORParser { do { let lower1 = UInt64(data[data.index(data.startIndex, offsetBy: 5)]) << 24 | UInt64(data[data.index(data.startIndex, offsetBy: 6)]) << 16 - let lower2 = UInt64(data[data.index(data.startIndex, offsetBy: 7)]) << 8 | + let lower2 = UInt64(data[data.index(data.startIndex, offsetBy: 7)]) << 8 | UInt64(data[data.index(data.startIndex, offsetBy: 8)]) lower = lower1 | lower2 diff --git a/Sources/CBORCoding/Half.swift b/Sources/CBORCoding/Half.swift index 60cd4f7..68857ef 100644 --- a/Sources/CBORCoding/Half.swift +++ b/Sources/CBORCoding/Half.swift @@ -1,5 +1,7 @@ import Foundation -#if !canImport(Half) -typealias Half = Float16 +#if canImport(Half) && swift(<5.3) +import Half + +typealias Float16 = Half #endif diff --git a/Tests/CBORCodingTests/CBORDecoderTests.swift b/Tests/CBORCodingTests/CBORDecoderTests.swift index 45488b6..7065962 100644 --- a/Tests/CBORCodingTests/CBORDecoderTests.swift +++ b/Tests/CBORCodingTests/CBORDecoderTests.swift @@ -5,12 +5,9 @@ // Copyright © 2021 SomeRandomiOSDev. All rights reserved. // -// swiftlint:disable nesting function_body_length force_cast identifier_name opening_brace comma implicitly_unwrapped_optional number_separator force_unwrapping +// swiftlint:disable nesting function_body_length force_cast identifier_name opening_brace comma implicitly_unwrapped_optional number_separator force_unwrapping closure_spacing @testable import CBORCoding -#if canImport(Half) -import Half -#endif import XCTest // MARK: - CBORDecoderTests Definition @@ -84,23 +81,23 @@ class CBORDecoderTests: XCTestCase { XCTAssertNoThrow(value = try decoder.decode(Int64.self, from: convertFromHexString("0x3B7FFFFFFFFFFFFFFF"))) // NOT part of RFC 8949 examples XCTAssertEqual(value as! Int64, .min) - XCTAssertNoThrow(value = try decoder.decode(Half.self, from: convertFromHexString("0xF90000"))) - XCTAssertEqual(value as! Half, 0.0) + XCTAssertNoThrow(value = try decoder.decode(Float16.self, from: convertFromHexString("0xF90000"))) + XCTAssertEqual(value as! Float16, 0.0) - XCTAssertNoThrow(value = try decoder.decode(Half.self, from: convertFromHexString("0xF98000"))) - XCTAssertEqual(value as! Half, -0.0) + XCTAssertNoThrow(value = try decoder.decode(Float16.self, from: convertFromHexString("0xF98000"))) + XCTAssertEqual(value as! Float16, -0.0) - XCTAssertNoThrow(value = try decoder.decode(Half.self, from: convertFromHexString("0xF93C00"))) - XCTAssertEqual(value as! Half, 1.0) + XCTAssertNoThrow(value = try decoder.decode(Float16.self, from: convertFromHexString("0xF93C00"))) + XCTAssertEqual(value as! Float16, 1.0) XCTAssertNoThrow(value = try decoder.decode(Double.self, from: convertFromHexString("0xFB3FF199999999999A"))) XCTAssertEqual(value as! Double, 1.1) - XCTAssertNoThrow(value = try decoder.decode(Half.self, from: convertFromHexString("0xF93E00"))) - XCTAssertEqual(value as! Half, 1.5) + XCTAssertNoThrow(value = try decoder.decode(Float16.self, from: convertFromHexString("0xF93E00"))) + XCTAssertEqual(value as! Float16, 1.5) - XCTAssertNoThrow(value = try decoder.decode(Half.self, from: convertFromHexString("0xF97BFF"))) - XCTAssertEqual(value as! Half, 65504.0) + XCTAssertNoThrow(value = try decoder.decode(Float16.self, from: convertFromHexString("0xF97BFF"))) + XCTAssertEqual(value as! Float16, 65504.0) XCTAssertNoThrow(value = try decoder.decode(Float.self, from: convertFromHexString("0xFA47C35000"))) XCTAssertEqual(value as! Float, 100000.0) @@ -111,23 +108,23 @@ class CBORDecoderTests: XCTestCase { XCTAssertNoThrow(value = try decoder.decode(Double.self, from: convertFromHexString("0xFB7E37E43C8800759C"))) XCTAssertEqual(value as! Double, 1.0e+300) - XCTAssertNoThrow(value = try decoder.decode(Half.self, from: convertFromHexString("0xF90001"))) - XCTAssertEqual(value as! Half, 5.960464477539063e-8) + XCTAssertNoThrow(value = try decoder.decode(Float16.self, from: convertFromHexString("0xF90001"))) + XCTAssertEqual(value as! Float16, 5.960464477539063e-8) - XCTAssertNoThrow(value = try decoder.decode(Half.self, from: convertFromHexString("0xF90400"))) - XCTAssertEqual(value as! Half, 0.00006103515625) + XCTAssertNoThrow(value = try decoder.decode(Float16.self, from: convertFromHexString("0xF90400"))) + XCTAssertEqual(value as! Float16, 0.00006103515625) - XCTAssertNoThrow(value = try decoder.decode(Half.self, from: convertFromHexString("0xF9C400"))) - XCTAssertEqual(value as! Half, -4.0) + XCTAssertNoThrow(value = try decoder.decode(Float16.self, from: convertFromHexString("0xF9C400"))) + XCTAssertEqual(value as! Float16, -4.0) XCTAssertNoThrow(value = try decoder.decode(Double.self, from: convertFromHexString("0xFBC010666666666666"))) XCTAssertEqual(value as! Double, -4.1) - // Half, Float, and Double should be able to decode each other's NaN values + // Float16, Float, and Double should be able to decode each other's NaN values for quietNaN in ["0xF97E00", "0xFA7FC00000", "0xFB7FF8000000000000"].map(convertFromHexString) { - XCTAssertNoThrow(value = try decoder.decode(Half.self, from: quietNaN)) - XCTAssertTrue((value as! Half).isNaN) - XCTAssertFalse((value as! Half).isSignalingNaN) + XCTAssertNoThrow(value = try decoder.decode(Float16.self, from: quietNaN)) + XCTAssertTrue((value as! Float16).isNaN) + XCTAssertFalse((value as! Float16).isSignalingNaN) XCTAssertNoThrow(value = try decoder.decode(Float.self, from: quietNaN)) XCTAssertTrue((value as! Float).isNaN) @@ -140,8 +137,8 @@ class CBORDecoderTests: XCTestCase { // NOT part of RFC 8949 examples for signalingNaN in ["0xF97D00", "0xFA7FA00000", "0xFB7FF4000000000000"].map(convertFromHexString) { - XCTAssertNoThrow(value = try decoder.decode(Half.self, from: signalingNaN)) - XCTAssertTrue((value as! Half).isSignalingNaN) + XCTAssertNoThrow(value = try decoder.decode(Float16.self, from: signalingNaN)) + XCTAssertTrue((value as! Float16).isSignalingNaN) XCTAssertNoThrow(value = try decoder.decode(Float.self, from: signalingNaN)) XCTAssertTrue((value as! Float).isSignalingNaN) @@ -150,11 +147,11 @@ class CBORDecoderTests: XCTestCase { XCTAssertTrue((value as! Double).isSignalingNaN) } - XCTAssertNoThrow(value = try decoder.decode(Half.self, from: convertFromHexString("0xF97C00"))) - XCTAssertEqual(value as! Half, .infinity) + XCTAssertNoThrow(value = try decoder.decode(Float16.self, from: convertFromHexString("0xF97C00"))) + XCTAssertEqual(value as! Float16, .infinity) - XCTAssertNoThrow(value = try decoder.decode(Half.self, from: convertFromHexString("0xF9FC00"))) - XCTAssertEqual(value as! Half, -.infinity) + XCTAssertNoThrow(value = try decoder.decode(Float16.self, from: convertFromHexString("0xF9FC00"))) + XCTAssertEqual(value as! Float16, -.infinity) XCTAssertNoThrow(value = try decoder.decode(Float.self, from: convertFromHexString("0xFA7F800000"))) XCTAssertEqual(value as! Float, .infinity) @@ -716,8 +713,8 @@ class CBORDecoderTests: XCTestCase { TestDecodeSingleValue.decode(from: convertFromHexString("0x3BFFFFFFFFFFFFFFFE")) { try $0.decode(UInt64.self) } // Decode unsigned from large signed TestDecodeSingleValue.decode(from: convertFromHexString("0x01")) { try $0.decode(String.self) } // Decode string from other type TestDecodeSingleValue.decode(from: convertFromHexString("0xFB3FF199999999999A")) { try $0.decode(Float.self) } // Precise Double into Float - TestDecodeSingleValue.decode(from: convertFromHexString("0xFB3FF199999999999A")) { try $0.decode(Float.self) } // Precise Double into Half - TestDecodeSingleValue.decode(from: convertFromHexString("0xFA3F8CCCCD")) { try $0.decode(Half.self) } // Precise Float into Half + TestDecodeSingleValue.decode(from: convertFromHexString("0xFB3FF199999999999A")) { try $0.decode(Float.self) } // Precise Double into Float16 + TestDecodeSingleValue.decode(from: convertFromHexString("0xFA3F8CCCCD")) { try $0.decode(Float16.self) } // Precise Float into Float16 } func testDecodeStringKeyedValues() { @@ -744,7 +741,7 @@ class CBORDecoderTests: XCTestCase { XCTAssertEqual(try container.decode(UInt16.self, forKey: .l), 25091) XCTAssertEqual(try container.decode(UInt32.self, forKey: .m), 2354019811) XCTAssertEqual(try container.decode(UInt64.self, forKey: .n), .max) - XCTAssertEqual(try container.decode(Half.self, forKey: .o), 1.0) + XCTAssertEqual(try container.decode(Float16.self, forKey: .o), 1.0) XCTAssertEqual(try container.decode(Float.self, forKey: .p), 100000.0) XCTAssertEqual(try container.decode(Double.self, forKey: .q), 1.1) XCTAssertEqual(try container.decode(String.self, forKey: .r), "CBOR") @@ -793,7 +790,7 @@ class CBORDecoderTests: XCTestCase { XCTAssertEqual(try container.decode(UInt16.self, forKey: .l), 25091) XCTAssertEqual(try container.decode(UInt32.self, forKey: .m), 2354019811) XCTAssertEqual(try container.decode(UInt64.self, forKey: .n), .max) - XCTAssertEqual(try container.decode(Half.self, forKey: .o), 1.0) + XCTAssertEqual(try container.decode(Float16.self, forKey: .o), 1.0) XCTAssertEqual(try container.decode(Float.self, forKey: .p), 100000.0) XCTAssertEqual(try container.decode(Double.self, forKey: .q), 1.1) XCTAssertEqual(try container.decode(String.self, forKey: .r), "CBOR") @@ -880,7 +877,7 @@ class CBORDecoderTests: XCTestCase { XCTAssertEqual(try container.decode(UInt16.self), 25091) XCTAssertEqual(try container.decode(UInt32.self), 2354019811) XCTAssertEqual(try container.decode(UInt64.self), .max) - XCTAssertEqual(try container.decode(Half.self), 1.0) + XCTAssertEqual(try container.decode(Float16.self), 1.0) XCTAssertEqual(try container.decode(Float.self), 100000.0) XCTAssertEqual(try container.decode(Double.self), 1.1) XCTAssertEqual(try container.decode(String.self), "CBOR") diff --git a/Tests/CBORCodingTests/CBOREncoderTests.swift b/Tests/CBORCodingTests/CBOREncoderTests.swift index 5d04f93..8bb32f9 100644 --- a/Tests/CBORCodingTests/CBOREncoderTests.swift +++ b/Tests/CBORCodingTests/CBOREncoderTests.swift @@ -8,9 +8,6 @@ // swiftlint:disable comma nesting function_body_length identifier_name force_try force_cast number_separator force_unwrapping @testable import CBORCoding -#if canImport(Half) -import Half -#endif import XCTest // MARK: - CBORTests Definition @@ -47,22 +44,22 @@ class CBOREncoderTests: XCTestCase { (try! encoder.encode(Int64(-100)), "0x3863"), (try! encoder.encode(Int64(-1000)), "0x3903E7"), (try! encoder.encode(Int64.min), "0x3B7FFFFFFFFFFFFFFF"), // NOT part of RFC 8949 examples - (try! encoder.encode(Half(0.0)), "0xF90000"), - (try! encoder.encode(Half(-0.0)), "0xF98000"), - (try! encoder.encode(Half(1.0)), "0xF93C00"), + (try! encoder.encode(Float16(0.0)), "0xF90000"), + (try! encoder.encode(Float16(-0.0)), "0xF98000"), + (try! encoder.encode(Float16(1.0)), "0xF93C00"), (try! encoder.encode(Double(1.1)), "0xFB3FF199999999999A"), - (try! encoder.encode(Half(1.5)), "0xF93E00"), - (try! encoder.encode(Half(65504.0)), "0xF97BFF"), + (try! encoder.encode(Float16(1.5)), "0xF93E00"), + (try! encoder.encode(Float16(65504.0)), "0xF97BFF"), (try! encoder.encode(Float(100000.0)), "0xFA47C35000"), (try! encoder.encode(Float(3.4028234663852886e+38)), "0xFA7F7FFFFF"), (try! encoder.encode(Double(1.0e+300)), "0xFB7E37E43C8800759C"), - (try! encoder.encode(Half(5.960464477539063e-8)), "0xF90001"), - (try! encoder.encode(Half(0.00006103515625)), "0xF90400"), - (try! encoder.encode(Half(-4.0)), "0xF9C400"), + (try! encoder.encode(Float16(5.960464477539063e-8)), "0xF90001"), + (try! encoder.encode(Float16(0.00006103515625)), "0xF90400"), + (try! encoder.encode(Float16(-4.0)), "0xF9C400"), (try! encoder.encode(Double(-4.1)), "0xFBC010666666666666"), - (try! encoder.encode(Half.infinity), "0xF97C00"), - (try! encoder.encode(Half.nan), "0xF97E00"), - (try! encoder.encode(-Half.infinity), "0xF9FC00"), + (try! encoder.encode(Float16.infinity), "0xF97C00"), + (try! encoder.encode(Float16.nan), "0xF97E00"), + (try! encoder.encode(-Float16.infinity), "0xF9FC00"), (try! encoder.encode(Float.infinity), "0xFA7F800000"), (try! encoder.encode(Float.nan), "0xFA7FC00000"), (try! encoder.encode(-Float.infinity), "0xFAFF800000"), diff --git a/Tests/CBORCodingTests/CBORParserTests.swift b/Tests/CBORCodingTests/CBORParserTests.swift index 5860f1b..af2db6d 100644 --- a/Tests/CBORCodingTests/CBORParserTests.swift +++ b/Tests/CBORCodingTests/CBORParserTests.swift @@ -8,9 +8,6 @@ // swiftlint:disable function_body_length force_cast comma force_try implicitly_unwrapped_optional number_separator force_unwrapping @testable import CBORCoding -#if canImport(Half) -import Half -#endif import XCTest // MARK: - CBORParserTests Definition @@ -114,28 +111,28 @@ class CBORParserTests: XCTestCase { XCTAssertEqual(value as! Int64, .min) XCTAssertNoThrow(value = try CBORParser.parse(convertFromHexString("0x\(prefix())F90000\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) - XCTAssertTrue(value is Half) - XCTAssertEqual(value as! Half, 0.0) + XCTAssertTrue(value is Float16) + XCTAssertEqual(value as! Float16, 0.0) XCTAssertNoThrow(value = try CBORParser.parse(convertFromHexString("0x\(prefix())F98000\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) - XCTAssertTrue(value is Half) - XCTAssertEqual(value as! Half, -0.0) + XCTAssertTrue(value is Float16) + XCTAssertEqual(value as! Float16, -0.0) XCTAssertNoThrow(value = try CBORParser.parse(convertFromHexString("0x\(prefix())F93C00\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) - XCTAssertTrue(value is Half) - XCTAssertEqual(value as! Half, 1.0) + XCTAssertTrue(value is Float16) + XCTAssertEqual(value as! Float16, 1.0) XCTAssertNoThrow(value = try CBORParser.parse(convertFromHexString("0x\(prefix())FB3FF199999999999A\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) XCTAssertTrue(value is Double) XCTAssertEqual(value as! Double, 1.1) XCTAssertNoThrow(value = try CBORParser.parse(convertFromHexString("0x\(prefix())F93E00\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) - XCTAssertTrue(value is Half) - XCTAssertEqual(value as! Half, 1.5) + XCTAssertTrue(value is Float16) + XCTAssertEqual(value as! Float16, 1.5) XCTAssertNoThrow(value = try CBORParser.parse(convertFromHexString("0x\(prefix())F97BFF\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) - XCTAssertTrue(value is Half) - XCTAssertEqual(value as! Half, 65504.0) + XCTAssertTrue(value is Float16) + XCTAssertEqual(value as! Float16, 65504.0) XCTAssertNoThrow(value = try CBORParser.parse(convertFromHexString("0x\(prefix())FA47C35000\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) XCTAssertTrue(value is Float) @@ -150,32 +147,32 @@ class CBORParserTests: XCTestCase { XCTAssertEqual(value as! Double, 1.0e+300) XCTAssertNoThrow(value = try CBORParser.parse(convertFromHexString("0x\(prefix())F90001\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) - XCTAssertTrue(value is Half) - XCTAssertEqual(value as! Half, 5.960464477539063e-8) + XCTAssertTrue(value is Float16) + XCTAssertEqual(value as! Float16, 5.960464477539063e-8) XCTAssertNoThrow(value = try CBORParser.parse(convertFromHexString("0x\(prefix())F90400\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) - XCTAssertTrue(value is Half) - XCTAssertEqual(value as! Half, 0.00006103515625) + XCTAssertTrue(value is Float16) + XCTAssertEqual(value as! Float16, 0.00006103515625) XCTAssertNoThrow(value = try CBORParser.parse(convertFromHexString("0x\(prefix())F9C400\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) - XCTAssertTrue(value is Half) - XCTAssertEqual(value as! Half, -4.0) + XCTAssertTrue(value is Float16) + XCTAssertEqual(value as! Float16, -4.0) XCTAssertNoThrow(value = try CBORParser.parse(convertFromHexString("0x\(prefix())FBC010666666666666\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) XCTAssertTrue(value is Double) XCTAssertEqual(value as! Double, -4.1) XCTAssertNoThrow(value = try CBORParser.parse(convertFromHexString("0x\(prefix())F97C00\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) - XCTAssertTrue(value is Half) - XCTAssertEqual(value as! Half, .infinity) + XCTAssertTrue(value is Float16) + XCTAssertEqual(value as! Float16, .infinity) XCTAssertNoThrow(value = try CBORParser.parse(convertFromHexString("0x\(prefix())F97E00\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) - XCTAssertTrue(value is Half) - XCTAssertTrue((value as! Half).isNaN) + XCTAssertTrue(value is Float16) + XCTAssertTrue((value as! Float16).isNaN) XCTAssertNoThrow(value = try CBORParser.parse(convertFromHexString("0x\(prefix())F9FC00\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) - XCTAssertTrue(value is Half) - XCTAssertEqual(value as! Half, -.infinity) + XCTAssertTrue(value is Float16) + XCTAssertEqual(value as! Float16, -.infinity) XCTAssertNoThrow(value = try CBORParser.parse(convertFromHexString("0x\(prefix())FA7F800000\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) XCTAssertTrue(value is Float) @@ -839,7 +836,7 @@ class CBORParserTests: XCTestCase { XCTAssertThrowsError(try CBORParser.parse(convertFromHexString("0x\(prefix())F8\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) // Simple - Missing extra byte XCTAssertThrowsError(try CBORParser.parse(convertFromHexString("0x\(prefix())FE\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) // Major Type 7, Unassigned code - XCTAssertThrowsError(try CBORParser.parse(convertFromHexString("0x\(prefix())F9\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) // Half - Missing two extra bytes + XCTAssertThrowsError(try CBORParser.parse(convertFromHexString("0x\(prefix())F9\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) // Float16 - Missing two extra bytes XCTAssertThrowsError(try CBORParser.parse(convertFromHexString("0x\(prefix())FA\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) // Float - Missing four extra bytes XCTAssertThrowsError(try CBORParser.parse(convertFromHexString("0x\(prefix())FB\(suffix())", prefixLength: prefixLength, suffixLength: suffixLength))) // Double - Missing eight extra bytes From 1e52c77523fca12cc290b17eed12fadb50ad72af Mon Sep 17 00:00:00 2001 From: Christoph Hagen Date: Sun, 29 Jan 2023 10:37:23 +0100 Subject: [PATCH 03/10] Delete Package.resolved --- Package.resolved | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 Package.resolved diff --git a/Package.resolved b/Package.resolved deleted file mode 100644 index 88442a7..0000000 --- a/Package.resolved +++ /dev/null @@ -1,16 +0,0 @@ -{ - "object": { - "pins": [ - { - "package": "Half", - "repositoryURL": "https://github.com/SomeRandomiOSDev/Half", - "state": { - "branch": null, - "revision": "8c80711c6ff57caa51e73e3b97a841c414af06cf", - "version": "1.3.1" - } - } - ] - }, - "version": 1 -} From d1f6ae0869f38e3e674e4a305598d4b57a6cf428 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Wed, 8 Nov 2023 19:07:28 -0800 Subject: [PATCH 04/10] Try to make it work on x64 macs --- Package.swift | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/Package.swift b/Package.swift index 91ec4ea..76960d0 100644 --- a/Package.swift +++ b/Package.swift @@ -1,27 +1,48 @@ // swift-tools-version:5.5 import PackageDescription +#if arch(x86_64) +let macOS = SupportedPlatform.macOS(.v10_10) +let macCatalyst = SupportedPlatform.macCatalyst(.v13) +#else +let macOS = SupportedPlatform.macOS(.v11) +let macCatalyst = SupportedPlatform.macCatalyst(.v14) +#endif + +#if (os(macOS) || targetEnvironment(macCatalyst)) && arch(x86_64) +// We still need Half +let halfPackage: [Package.Dependency] = [ + .package(url: "https://github.com/SomeRandomiOSDev/Half", from: "1.3.1") +] +let halfTarget: [Target.Dependency] = ["Half"] +#else +let halfPackage: [Package.Dependency] = [] +let halfTarget: [Target.Dependency] = [] +#endif + + + let package = Package( name: "CBORCoding", platforms: [ .iOS(.v14), - .macOS(.v11), + macOS, .tvOS(.v14), .watchOS(.v7), - .macCatalyst(.v14), + macCatalyst, ], products: [ .library(name: "CBORCoding", targets: ["CBORCoding"]) ], - dependencies: [], + dependencies: halfPackage, targets: [ - .target(name: "CBORCoding", dependencies: []), - .testTarget(name: "CBORCodingTests", dependencies: ["CBORCoding"]) + .target(name: "CBORCoding", dependencies: halfTarget), + .testTarget(name: "CBORCodingTests", dependencies: ["CBORCoding"] + halfTarget) ], - swiftLanguageVersions: [.v5] + swiftLanguageVersions: [.version("4.2"), .version("5")] ) From 6f0d36a9e731fc9626c52c50f086a882fb00ea6e Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Thu, 9 Nov 2023 10:35:16 -0800 Subject: [PATCH 05/10] Make sure we get typealias Float16 = Half when we need it --- Sources/CBORCoding/Half.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/CBORCoding/Half.swift b/Sources/CBORCoding/Half.swift index 68857ef..c2865d7 100644 --- a/Sources/CBORCoding/Half.swift +++ b/Sources/CBORCoding/Half.swift @@ -1,6 +1,7 @@ import Foundation -#if canImport(Half) && swift(<5.3) +#if canImport(Half) && swift(<5.3) || ( + os(macOS) || targetEnvironment(macCatalyst)) && arch(x86_64) import Half typealias Float16 = Half From 42dbf54aa09531eb060b55dcd04238b93f183af9 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Thu, 9 Nov 2023 10:37:17 -0800 Subject: [PATCH 06/10] Restore Package.resolved --- Package.resolved | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 Package.resolved diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 0000000..7116ac1 --- /dev/null +++ b/Package.resolved @@ -0,0 +1,16 @@ +{ + "object": { + "pins": [ + { + "package": "Half", + "repositoryURL": "https://github.com/SomeRandomiOSDev/Half", + "state": { + "branch": null, + "revision": "9f95ddc774eefae46d92492ed8d49457dcf031f4", + "version": "1.3.2" + } + } + ] + }, + "version": 1 +} From db6d030cffcb51e84e638477b2bb6437fae0b0e5 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 12 Nov 2023 20:52:13 -0500 Subject: [PATCH 07/10] Major version bump These changes will break anyone depending on (de)coding Half on ARM architectures. --- CBORCoding.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CBORCoding.podspec b/CBORCoding.podspec index 47a3b45..1a08bc0 100644 --- a/CBORCoding.podspec +++ b/CBORCoding.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "CBORCoding" - s.version = "1.3.2" + s.version = "1.4.0" s.summary = "A CBOR Encoder and Decoder" s.description = <<-DESC A lightweight framework containing a coder pair for encoding and decoding `Codable` conforming types to and from CBOR document format for iOS, macOS, tvOS, and watchOS. From eeadc3fbbb69ba55df2b27fde83d427db31908c5 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 12 Nov 2023 21:00:05 -0500 Subject: [PATCH 08/10] Update docs --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 080cde7..c6bf1dd 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,10 @@ let decoder = CBORDecoder() let stinger = try decoder.decode(Car.self, from: encodedData) ``` +## 16-bit Floating Point Support + +This package supports encoding/decoding Swift's `Float16` where available. Unfortunately that does not include macOS on Intel processors, where an almost-identical type [`Half`](https://github.com/SomeRandomiOSDev/Half) is supported instead. + ## CBOR **Concise Binary Object Representation** is a data format for being able to encode formatted data with a goal of a having as small a message size as possible. From 782e21918697e470af9ac54019f249a87c7f6ecb Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 13 Nov 2023 11:49:40 -0800 Subject: [PATCH 09/10] Satisfy the linter --- Package.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Package.swift b/Package.swift index 76960d0..b4c4c1a 100644 --- a/Package.swift +++ b/Package.swift @@ -20,8 +20,6 @@ let halfPackage: [Package.Dependency] = [] let halfTarget: [Target.Dependency] = [] #endif - - let package = Package( name: "CBORCoding", @@ -30,7 +28,7 @@ let package = Package( macOS, .tvOS(.v14), .watchOS(.v7), - macCatalyst, + macCatalyst ], products: [ From 02018a0fdcf0d0eca3c0d784de88c74a8bb8d7f1 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Tue, 14 Nov 2023 14:28:54 -0800 Subject: [PATCH 10/10] Keep Half as a package dependency as long as it's needed on Intel Mac Otherwise it gets deleted from Package.resolved --- Package.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Package.swift b/Package.swift index b4c4c1a..2c14ff5 100644 --- a/Package.swift +++ b/Package.swift @@ -11,15 +11,15 @@ let macCatalyst = SupportedPlatform.macCatalyst(.v14) #if (os(macOS) || targetEnvironment(macCatalyst)) && arch(x86_64) // We still need Half -let halfPackage: [Package.Dependency] = [ - .package(url: "https://github.com/SomeRandomiOSDev/Half", from: "1.3.1") -] let halfTarget: [Target.Dependency] = ["Half"] #else -let halfPackage: [Package.Dependency] = [] let halfTarget: [Target.Dependency] = [] #endif +let halfPackage: [Package.Dependency] = [ + .package(url: "https://github.com/SomeRandomiOSDev/Half", from: "1.3.1") +] + let package = Package( name: "CBORCoding",