Skip to content

Instantly share code, notes, and snippets.

@IanKeen
Last active March 23, 2023 18:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save IanKeen/890910d344d9cab9b2ab2ec409370e14 to your computer and use it in GitHub Desktop.
Save IanKeen/890910d344d9cab9b2ab2ec409370e14 to your computer and use it in GitHub Desktop.
Combined: A type composed of other types (potential alternative to my Partial<T> type)
@dynamicMemberLookup
struct Combined<A, B> {
private let a: A
private let b: B
init(a: A, b: B) { (self.a, self.b) = (a, b) }
subscript<T>(dynamicMember keyPath: KeyPath<A, T>) -> T {
return a[keyPath: keyPath]
}
subscript<T>(dynamicMember keyPath: KeyPath<B, T>) -> T {
return b[keyPath: keyPath]
}
}
extension Combined: Encodable where A: Encodable, B: Encodable {
func encode(to encoder: Encoder) throws {
try a.encode(to: encoder)
try b.encode(to: encoder)
}
}
extension Combined: Decodable where A: Decodable, B: Decodable {
init(from decoder: Decoder) throws {
try self.init(
a: A(from: decoder),
b: B(from: decoder)
)
}
}
struct A: Codable { var a: Int }
struct B: Codable { var b: Int }
struct C: Codable { var c: Int }
let json = """
{"a": 1, "b": 2, "c": 3}
"""
let decoded = try! JSONDecoder().decode(Combined<A, Combined<B, C>>.self, from: Data(json.utf8))
print(decoded.a, decoded.b, decoded.c) // 1 2 3
let string = try! String(data: JSONEncoder().encode(decoded), encoding: .utf8)!
print(string) // {"a":1,"b":2,"c":3}
struct Foo: Equatable { let fooValue: String }
struct Bar: Equatable { let barValue: String }
struct Baz: Equatable { let bazValue: String }
typealias Step1 = Combined<Void, Foo>
typealias Step2 = Combined<Step1, Bar>
typealias Step3 = Combined<Step2, Baz>
let step1 = Step1(a: (), b: .init(fooValue: "foo"))
step1.fooValue // foo
let step2 = Step2(a: step1, b: .init(barValue: "bar"))
step2.fooValue // foo
step2.barValue // bar
let step3 = Step3(a: step2, b: .init(bazValue: "baz"))
step3.fooValue // foo
step3.barValue // bar
step3.bazValue // baz
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment