From fb72db46a737bceae1643948eeb1d4542e84a175 Mon Sep 17 00:00:00 2001 From: cnkwocha Date: Fri, 29 Nov 2024 16:35:40 +0000 Subject: [PATCH] Fix Integer type serialization for 32-bit platforms Motivation: [RFC 9651](https://www.ietf.org/rfc/rfc9651.html) permits serializing an integer in the range of -999,999,999,999,999 to 999,999,999,999,999 inclusive ([Section 4.1.4-2.1.1](https://www.ietf.org/rfc/rfc9651.html#section-4.1.4-2.1.1)). As `RFC9651BareItem` takes values `integer` or `date` with an associated value of type `Int`, that range is implicitly more constrained on 32-bit platforms to a subset range of `-Int32.min` to `Int32.max` inclusive. Modifications: - Adjust `RFC9651BareItem` to take values `integer` or `date` with an associated value of type `Int64` instead, which is sufficient for the permitted range. Result: Compatibility for the Integer and Date Structured Types on 32-bit platforms. --- .../RawStructuredFieldValues/ComponentTypes.swift | 10 +++++----- Sources/RawStructuredFieldValues/FieldParser.swift | 4 ++-- .../Encoder/StructuredFieldValueEncoder.swift | 12 ++++++------ Tests/StructuredFieldValuesTests/Fixtures.swift | 4 ++-- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Sources/RawStructuredFieldValues/ComponentTypes.swift b/Sources/RawStructuredFieldValues/ComponentTypes.swift index 7fdae33..5e641e1 100644 --- a/Sources/RawStructuredFieldValues/ComponentTypes.swift +++ b/Sources/RawStructuredFieldValues/ComponentTypes.swift @@ -94,7 +94,7 @@ extension BareItem { self = .bool(b) case .integer(let i): - self = .integer(i) + self = .integer(Int(i)) case .decimal(let d): self = .decimal(d) @@ -126,7 +126,7 @@ public enum RFC9651BareItem: Sendable { case bool(Bool) /// An integer item. - case integer(Int) + case integer(Int64) /// A decimal item. case decimal(PseudoDecimal) @@ -142,7 +142,7 @@ public enum RFC9651BareItem: Sendable { case token(String) /// A date item. - case date(Int) + case date(Int64) /// A display string item. case displayString(String) @@ -155,7 +155,7 @@ extension RFC9651BareItem: ExpressibleByBooleanLiteral { } extension RFC9651BareItem: ExpressibleByIntegerLiteral { - public init(integerLiteral value: Int) { + public init(integerLiteral value: Int64) { self = .integer(value) } } @@ -184,7 +184,7 @@ extension RFC9651BareItem { self = .bool(b) case .integer(let i): - self = .integer(i) + self = .integer(Int64(i)) case .decimal(let d): self = .decimal(d) diff --git a/Sources/RawStructuredFieldValues/FieldParser.swift b/Sources/RawStructuredFieldValues/FieldParser.swift index 99549e1..9fed003 100644 --- a/Sources/RawStructuredFieldValues/FieldParser.swift +++ b/Sources/RawStructuredFieldValues/FieldParser.swift @@ -232,7 +232,7 @@ extension StructuredFieldValueParser { } private mutating func _parseAnIntegerOrDecimal(isDate: Bool) throws -> RFC9651BareItem { - var sign = 1 + var sign = Int64(1) var type = IntegerOrDecimal.integer if let first = self.underlyingData.first, first == asciiDash { @@ -304,7 +304,7 @@ extension StructuredFieldValueParser { case .integer: // This intermediate string is sad, we should rewrite this manually to avoid it. // This force-unwrap is safe, as we have validated that all characters are ascii digits. - let baseInt = Int(String(decoding: integerBytes, as: UTF8.self), radix: 10)! + let baseInt = Int64(String(decoding: integerBytes, as: UTF8.self), radix: 10)! let resultingInt = baseInt * sign if isDate { diff --git a/Sources/StructuredFieldValues/Encoder/StructuredFieldValueEncoder.swift b/Sources/StructuredFieldValues/Encoder/StructuredFieldValueEncoder.swift index 7c56dee..ca38813 100644 --- a/Sources/StructuredFieldValues/Encoder/StructuredFieldValueEncoder.swift +++ b/Sources/StructuredFieldValues/Encoder/StructuredFieldValueEncoder.swift @@ -313,7 +313,7 @@ extension _StructuredFieldEncoder: SingleValueEncodingContainer { } func encode(_ data: Date) throws { - let date = Int(data.timeIntervalSince1970) + let date = Int64(data.timeIntervalSince1970) try self.currentStackEntry.storage.insertBareItem(.date(date)) } @@ -371,7 +371,7 @@ extension _StructuredFieldEncoder: SingleValueEncodingContainer { } private func _encodeFixedWidthInteger(_ value: T) throws { - guard let base = Int(exactly: value) else { + guard let base = Int64(exactly: value) else { throw StructuredHeaderError.integerOutOfRange } try self.currentStackEntry.storage.insertBareItem(.integer(base)) @@ -483,7 +483,7 @@ extension _StructuredFieldEncoder { } func append(_ value: Date) throws { - let date = Int(value.timeIntervalSince1970) + let date = Int64(value.timeIntervalSince1970) try self.currentStackEntry.storage.appendBareItem(.date(date)) } @@ -562,7 +562,7 @@ extension _StructuredFieldEncoder { } private func _appendFixedWidthInteger(_ value: T) throws { - guard let base = Int(exactly: value) else { + guard let base = Int64(exactly: value) else { throw StructuredHeaderError.integerOutOfRange } try self.currentStackEntry.storage.appendBareItem(.integer(base)) @@ -667,7 +667,7 @@ extension _StructuredFieldEncoder { func encode(_ value: Date, forKey key: String) throws { let key = self.sanitizeKey(key) - let date = Int(value.timeIntervalSince1970) + let date = Int64(value.timeIntervalSince1970) try self.currentStackEntry.storage.insertBareItem(.date(date), atKey: key) } @@ -789,7 +789,7 @@ extension _StructuredFieldEncoder { } private func _encodeFixedWidthInteger(_ value: T, forKey key: String) throws { - guard let base = Int(exactly: value) else { + guard let base = Int64(exactly: value) else { throw StructuredHeaderError.integerOutOfRange } try self.currentStackEntry.storage.insertBareItem(.integer(base), atKey: key) diff --git a/Tests/StructuredFieldValuesTests/Fixtures.swift b/Tests/StructuredFieldValuesTests/Fixtures.swift index b647a9b..8f4b204 100644 --- a/Tests/StructuredFieldValuesTests/Fixtures.swift +++ b/Tests/StructuredFieldValuesTests/Fixtures.swift @@ -119,7 +119,7 @@ struct StructuredHeaderTestFixture: Decodable { enum JSONSchema: Decodable { case dictionary([String: JSONSchema]) case array([JSONSchema]) - case integer(Int) + case integer(Int64) case double(Double) case string(String) case bool(Bool) @@ -130,7 +130,7 @@ enum JSONSchema: Decodable { self = .string(value) } else if let bool = try? container.decode(Bool.self) { self = .bool(bool) - } else if let value = try? container.decode(Int.self) { + } else if let value = try? container.decode(Int64.self) { self = .integer(value) } else if let value = try? container.decode(Double.self) { self = .double(value)