Skip to content

Commit

Permalink
#45: Switch from Int ids to UInt ids if overflow happens and the id i…
Browse files Browse the repository at this point in the history
…s not negative
  • Loading branch information
trasch committed Mar 19, 2024
1 parent 30e1e1f commit b1c710a
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 14 deletions.
23 changes: 23 additions & 0 deletions Sources/GISTools/Extensions/FeatureIdentifierExtensions.swift
Original file line number Diff line number Diff line change
@@ -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
}
}

}
56 changes: 42 additions & 14 deletions Sources/GISTools/GeoJson/Feature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}
Expand Down
18 changes: 18 additions & 0 deletions Tests/GISToolsTests/GeoJson/FeatureTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

}

0 comments on commit b1c710a

Please sign in to comment.