diff --git a/Sources/GISTools/Extensions/FeatureIdentifierExtensions.swift b/Sources/GISTools/Extensions/FeatureIdentifierExtensions.swift new file mode 100644 index 0000000..4bf5a14 --- /dev/null +++ b/Sources/GISTools/Extensions/FeatureIdentifierExtensions.swift @@ -0,0 +1,23 @@ +import Foundation + +// MARK: Public + +extension Feature.Identifier { + + public var int64Value: Int64? { + switch self { + case .int(let int): Int64(exactly: int) + case .uint(let uint): Int64(exactly: uint) + default: nil + } + } + + public var uint64Value: UInt64? { + switch self { + case .int(let int): UInt64(exactly: int) + case .uint(let uint): UInt64(exactly: uint) + default: nil + } + } + +} diff --git a/Sources/GISTools/GeoJson/Feature.swift b/Sources/GISTools/GeoJson/Feature.swift index f9f1f5c..cf71cb3 100644 --- a/Sources/GISTools/GeoJson/Feature.swift +++ b/Sources/GISTools/GeoJson/Feature.swift @@ -5,39 +5,67 @@ public struct Feature: GeoJson { /// A GeoJSON identifier that can either be a string or number. public enum Identifier: Equatable, Hashable, CustomStringConvertible, Sendable { + +#if _pointerBitWidth(_32) + public typealias IntId = Int64 + public typealias UIntId = UInt64 +#else + public typealias IntId = Int + public typealias UIntId = UInt +#endif + case string(String) - case int(Int) + case int(IntId) + case uint(UIntId) case double(Double) public init?(value: Any?) { guard let value else { return nil } - if let int = value as? Int { + + switch value { + case let int as IntId: self = .int(int) - } - else if let string = value as? String { + + case let uint as UIntId: + self = .uint(uint) + + case let string as String: self = .string(string) - } - else if let double = value as? Double { + + case let double as Double: self = .double(double) - } - else { + + case let binaryInt as (any BinaryInteger): + if let int = IntId(exactly: binaryInt) { + self = .int(int) + } + else if let uint = UIntId(exactly: binaryInt) { + self = .uint(uint) + } + else { + return nil + } + + default: return nil } } public var asJson: Any { switch self { - case .double(let double): return double - case .int(let int): return int - case .string(let string): return string + case .double(let double): double + case .int(let int): int + case .uint(let uint): uint + case .string(let string): string } } public var description: String { switch self { - case .double(let double): return String(double) - case .int(let int): return String(int) - case .string(let string): return string + case .double(let double): String(double) + case .int(let int): String(int) + case .uint(let uint): String(uint) + case .string(let string): string } } } diff --git a/Tests/GISToolsTests/GeoJson/FeatureTests.swift b/Tests/GISToolsTests/GeoJson/FeatureTests.swift index a585fc4..4dacd1d 100644 --- a/Tests/GISToolsTests/GeoJson/FeatureTests.swift +++ b/Tests/GISToolsTests/GeoJson/FeatureTests.swift @@ -105,4 +105,22 @@ final class FeatureTests: XCTestCase { XCTAssertEqual(featureData, feature.asJsonData(prettyPrinted: true)) } + func testFeatureIds() throws { + XCTAssertEqual(Feature.Identifier(value: Int8(32)), .int(32)) + XCTAssertEqual(Feature.Identifier(value: Int8(32))?.int64Value, 32) + XCTAssertEqual(Feature.Identifier(value: Int8(32))?.uint64Value, 32) + + XCTAssertEqual(Feature.Identifier(value: Int8(-32)), .int(-32)) + XCTAssertEqual(Feature.Identifier(value: Int8(-32))?.int64Value, -32) + XCTAssertNil(Feature.Identifier(value: Int8(-32))?.uint64Value) + + XCTAssertEqual(Feature.Identifier(value: Int64.max), .int(9223372036854775807)) + XCTAssertEqual(Feature.Identifier(value: Int64.max)?.int64Value, 9223372036854775807) + + // 9223372036854775808 is Int64.max+1 + XCTAssertEqual(Feature.Identifier(value: UInt64(9223372036854775808)), .uint(9223372036854775808)) + XCTAssertNil(Feature.Identifier(value: UInt64(9223372036854775808))?.int64Value) + XCTAssertEqual(Feature.Identifier(value: UInt64(9223372036854775808))?.uint64Value, 9223372036854775808) + } + }