Skip to content

Commit ed83ec1

Browse files
feature: Adds special number JSON codings
1 parent d8f791f commit ed83ec1

File tree

3 files changed

+59
-22
lines changed

3 files changed

+59
-22
lines changed

Sources/Haystack/Number.swift

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,36 @@ extension Number {
6969
)
7070
}
7171

72-
self.val = try container.decode(Double.self, forKey: .val)
73-
self.unit = try container.decode(String?.self, forKey: .unit)
72+
if let val = try? container.decode(Double.self, forKey: .val) {
73+
self.val = val
74+
self.unit = try container.decode(String?.self, forKey: .unit)
75+
} else if let val = try? container.decode(String.self, forKey: .val) {
76+
self.unit = nil
77+
switch val {
78+
case "INF":
79+
self.val = .infinity
80+
case "-INF":
81+
self.val = -1.0 * .infinity
82+
case "NaN":
83+
self.val = .nan
84+
default:
85+
throw DecodingError.typeMismatch(
86+
Self.self,
87+
.init(
88+
codingPath: [Self.CodingKeys.val],
89+
debugDescription: "String `val` must be either `INF`, `-INF`, or `NaN`, not \(val)"
90+
)
91+
)
92+
}
93+
} else {
94+
throw DecodingError.typeMismatch(
95+
Self.self,
96+
.init(
97+
codingPath: [Self.CodingKeys.val],
98+
debugDescription: "Expected `val` to be either Double or String"
99+
)
100+
)
101+
}
74102
} else if let container = try? decoder.singleValueContainer() {
75103
self.val = try container.decode(Double.self)
76104
self.unit = nil
@@ -89,8 +117,19 @@ extension Number {
89117
if unit != nil || val.isNaN || val.isInfinite {
90118
var container = encoder.container(keyedBy: Self.CodingKeys)
91119
try container.encode(Self.kindValue, forKey: ._kind)
92-
try container.encode(val, forKey: .val)
93-
try container.encode(unit, forKey: .unit)
120+
121+
if val.isNaN {
122+
try container.encode("NaN", forKey: .val)
123+
} else if val.isInfinite {
124+
if val > 0 {
125+
try container.encode("INF", forKey: .val)
126+
} else {
127+
try container.encode("-INF", forKey: .val)
128+
}
129+
} else {
130+
try container.encode(val, forKey: .val)
131+
try container.encode(unit, forKey: .unit)
132+
}
94133
} else {
95134
var container = encoder.singleValueContainer()
96135
try container.encode(val)

Tests/HaystackTests/IO/ZincTokenizerTests.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ final class ZincTokenizerTests: XCTestCase {
6565
try XCTAssertEqualTokensAndVals(zinc: "12:00:12.001", expected: [(.time, Time(hour: 12, minute: 0, second: 12, millisecond: 1))])
6666
}
6767

68-
// TODO: Fix these!
6968
func testDateTime() throws {
7069
try XCTAssertEqualTokensAndVals(
7170
zinc: "2016-01-13T09:51:33-05:00 New_York",

Tests/HaystackTests/NumberTests.swift

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,23 +36,22 @@ final class NumberTests: XCTestCase {
3636
)
3737
}
3838

39-
// TODO: Fix this test
40-
// func testJsonCoding_infinity() throws {
41-
// let value = Number(val: .infinity)
42-
// let jsonString = #"{"_kind":"number","val":"INF"}"#
43-
//
44-
// let encodedData = try JSONEncoder().encode(value)
45-
// XCTAssertEqual(
46-
// String(data: encodedData, encoding: .utf8),
47-
// jsonString
48-
// )
49-
//
50-
// let decodedData = try XCTUnwrap(jsonString.data(using: .utf8))
51-
// XCTAssertEqual(
52-
// try JSONDecoder().decode(Number.self, from: decodedData),
53-
// value
54-
// )
55-
// }
39+
func testJsonCoding_infinity() throws {
40+
let value = Number(.infinity)
41+
let jsonString = #"{"_kind":"number","val":"INF"}"#
42+
43+
let encodedData = try JSONEncoder().encode(value)
44+
XCTAssertEqual(
45+
String(data: encodedData, encoding: .utf8),
46+
jsonString
47+
)
48+
49+
let decodedData = try XCTUnwrap(jsonString.data(using: .utf8))
50+
XCTAssertEqual(
51+
try JSONDecoder().decode(Number.self, from: decodedData),
52+
value
53+
)
54+
}
5655

5756
func testToZinc() throws {
5857
XCTAssertEqual(

0 commit comments

Comments
 (0)