Skip to content

Commit 95551e5

Browse files
@dynamicMemberLookup brought back for backward compatibility, ConfigTests/ConfigEquatable, Condig.Data equality improved
1 parent 5d5beec commit 95551e5

File tree

2 files changed

+248
-188
lines changed

2 files changed

+248
-188
lines changed

Sources/Hub/Config.swift

+118-60
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import OrderedCollections
99

1010
// MARK: - Configuration files with dynamic lookup
1111

12+
@dynamicMemberLookup
1213
public struct Config: Hashable, Sendable,
1314
ExpressibleByStringLiteral,
1415
ExpressibleByIntegerLiteral,
@@ -36,23 +37,57 @@ public struct Config: Hashable, Sendable,
3637

3738
public static func == (lhs: Data, rhs: Data) -> Bool {
3839
switch (lhs, rhs) {
39-
case (.string(let lhs), .string(let rhs)):
40-
return lhs == rhs
41-
case (.integer(let lhs), .integer(let rhs)):
42-
return lhs == rhs
43-
case (.boolean(let lhs), .boolean(let rhs)):
44-
return lhs == rhs
45-
case (.floating(let lhs), .floating(let rhs)):
46-
return lhs == rhs
40+
case (.null, .null):
41+
return true
42+
case (.string(let lhs), _):
43+
if let rhs = rhs.string() {
44+
return lhs == BinaryDistinctString(rhs)
45+
}
46+
case (.integer(let lhs), _):
47+
if let rhs = rhs.integer() {
48+
return lhs == rhs
49+
}
50+
case (.boolean(let lhs), _):
51+
if let rhs = rhs.boolean() {
52+
return lhs == rhs
53+
}
54+
case (.floating(let lhs), _):
55+
if let rhs = rhs.floating() {
56+
return lhs == rhs
57+
}
4758
case (.dictionary(let lhs), .dictionary(let rhs)):
48-
return lhs == rhs // TODO: ensure equatable
59+
return lhs == rhs
4960
case (.array(let lhs), .array(let rhs)):
50-
return lhs == rhs // TODO: ensure equatable
61+
return lhs == rhs
5162
case (.token(let lhs), .token(let rhs)):
52-
return lhs == rhs // TODO: ensure equatable
63+
return lhs == rhs
64+
default:
65+
return false
66+
}
67+
68+
// right hand side might be a super set of left hand side
69+
switch rhs {
70+
case .string(let rhs):
71+
if let lhs = lhs.string() {
72+
return BinaryDistinctString(lhs) == rhs
73+
}
74+
case .integer(let rhs):
75+
if let lhs = lhs.integer() {
76+
return lhs == rhs
77+
}
78+
case .boolean(let rhs):
79+
if let lhs = lhs.boolean() {
80+
return lhs == rhs
81+
}
82+
case .floating(let rhs):
83+
if let lhs = lhs.floating() {
84+
return lhs == rhs
85+
}
5386
default:
5487
return false
5588
}
89+
90+
return false
5691
}
5792

5893
public var description: String {
@@ -75,6 +110,52 @@ public struct Config: Hashable, Sendable,
75110
return "(\(val.0), \(val.1))"
76111
}
77112
}
113+
114+
115+
public func string() -> String? {
116+
if case .string(let val) = self {
117+
return val.string
118+
}
119+
return nil
120+
}
121+
122+
123+
public func boolean() -> Bool? {
124+
if case .boolean(let val) = self {
125+
return val
126+
}
127+
if case .integer(let val) = self {
128+
return val == 1
129+
}
130+
if case .string(let val) = self {
131+
switch val.string.lowercased() {
132+
case "true", "t", "1":
133+
return true
134+
case "false", "f", "0":
135+
return false
136+
default:
137+
return nil
138+
}
139+
}
140+
return nil
141+
}
142+
143+
public func integer() -> Int? {
144+
if case .integer(let val) = self {
145+
return val
146+
}
147+
return nil
148+
}
149+
150+
public func floating() -> Float? {
151+
if case .floating(let val) = self {
152+
return val
153+
}
154+
if case .integer(let val) = self {
155+
return Float(val)
156+
}
157+
return nil
158+
}
78159
}
79160

80161
init() {
@@ -218,12 +299,9 @@ public struct Config: Hashable, Sendable,
218299
}
219300

220301
public func string() -> String? {
221-
if case .string(let val) = self.value {
222-
return val.string
223-
}
224-
return nil
302+
return self.value.string()
225303
}
226-
304+
227305
public func string(or: String) -> String {
228306
if let val: String = self.string() {
229307
return val
@@ -264,25 +342,9 @@ public struct Config: Hashable, Sendable,
264342
}
265343

266344
public func boolean() -> Bool? {
267-
if case .boolean(let val) = self.value {
268-
return val
269-
}
270-
if case .integer(let val) = self.value {
271-
return val == 1
272-
}
273-
if case .string(let val) = self.value {
274-
switch val.string.lowercased() {
275-
case "true", "t", "1":
276-
return true
277-
case "false", "f", "0":
278-
return false
279-
default:
280-
return nil
281-
}
282-
}
283-
return nil
345+
return self.value.boolean()
284346
}
285-
347+
286348
public func boolean(or: Bool) -> Bool {
287349
if let val = self.boolean() {
288350
return val
@@ -301,13 +363,10 @@ public struct Config: Hashable, Sendable,
301363
}
302364

303365
public func integer() -> Int? {
304-
if case .integer(let val) = self.value {
305-
return val
306-
}
307-
return nil
366+
return self.value.integer()
308367
}
309-
310-
public func integer(or: Int) -> Int? {
368+
369+
public func integer(or: Int) -> Int {
311370
if let val = self.integer() {
312371
return val
313372
}
@@ -317,25 +376,19 @@ public struct Config: Hashable, Sendable,
317376
// MARK: getters/operators - floating
318377

319378
public func get() -> Float? {
320-
return self.floating()
379+
return self.value.floating()
321380
}
322381

323382
public func get(or: Float) -> Float? {
324383
return self.floating(or: or)
325384
}
326385

327386
public func floating() -> Float? {
328-
if case .floating(let val) = self.value {
329-
return val
330-
}
331-
if case .integer(let val) = self.value {
332-
return Float(val)
333-
}
334-
return nil
387+
return self.value.floating()
335388
}
336-
337-
public func floating(or: Float) -> Float? {
338-
if let val = self.floating() {
389+
390+
public func floating(or: Float) -> Float {
391+
if let val = self.value.floating() {
339392
return val
340393
}
341394
return or
@@ -346,7 +399,7 @@ public struct Config: Hashable, Sendable,
346399
public func get() -> [BinaryDistinctString: Int]? {
347400
if let dict = self.dictionary() {
348401
return dict.reduce(into: [:]) { result, element in
349-
if let val = element.value.integer() {
402+
if let val = element.value.value.integer() {
350403
result[element.key] = val
351404
}
352405
}
@@ -407,7 +460,7 @@ public struct Config: Hashable, Sendable,
407460
public func get() -> [String]? {
408461
if let arr = self.array() {
409462
return arr.reduce(into: []) { result, element in
410-
if let val: String = element.string() {
463+
if let val: String = element.value.string() {
411464
result.append(val)
412465
}
413466
}
@@ -511,6 +564,17 @@ public struct Config: Hashable, Sendable,
511564
return Config()
512565
}
513566
}
567+
568+
569+
public subscript(dynamicMember member: String) -> Config? {
570+
get {
571+
if let dict = self.dictionary() {
572+
return dict[BinaryDistinctString(member)] ?? dict[self.uncamelCase(BinaryDistinctString(member))] ?? Config()
573+
}
574+
575+
return nil // backward compatibility
576+
}
577+
}
514578

515579
func uncamelCase(_ string: BinaryDistinctString) -> BinaryDistinctString {
516580
let scalars = string.string.unicodeScalars
@@ -684,13 +748,7 @@ extension Config: Codable {
684748

685749
extension Config: Equatable {
686750
public static func == (lhs: Config, rhs: Config) -> Bool {
687-
let encoder = JSONEncoder()
688-
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
689-
690-
guard let lhsData = try? encoder.encode(lhs),
691-
let rhsData = try? encoder.encode(rhs)
692-
else { return false }
693-
return lhsData == rhsData
751+
return lhs.value == rhs.value
694752
}
695753
}
696754

0 commit comments

Comments
 (0)