Skip to content

Instantly share code, notes, and snippets.

@5sw
Created July 21, 2021 09:18
Show Gist options
  • Save 5sw/ead2b6015a5e14cb5f6b90002983e81b to your computer and use it in GitHub Desktop.
Save 5sw/ead2b6015a5e14cb5f6b90002983e81b to your computer and use it in GitHub Desktop.
Automatic builder for any Swift type
@dynamicMemberLookup
struct Configurator<T> {
var configure: (inout T) -> Void = { _ in }
subscript<V>(dynamicMember keyPath: WritableKeyPath<T, V>) -> Builder<V> {
.init(configure: configure, keyPath: keyPath)
}
static subscript<V>(dynamicMember keyPath: WritableKeyPath<T, V>) -> Builder<V> {
.init(configure: { _ in }, keyPath: keyPath)
}
@dynamicMemberLookup
struct Builder<V> {
var configure: (inout T) -> Void
var keyPath: WritableKeyPath<T, V>
func callAsFunction(_ value: V) -> Configurator {
return .init { [configure, keyPath] object in
configure(&object)
object[keyPath: keyPath] = value
}
}
subscript<C>(dynamicMember childKeyPath: WritableKeyPath<V, C>) -> Builder<C> {
.init(configure: configure, keyPath: keyPath.appending(path: childKeyPath))
}
}
func apply(_ value: inout T) {
configure(&value)
}
}
protocol DefaultConstructible {
init()
}
extension Configurator where T: DefaultConstructible {
func build() -> T {
var result = T()
apply(&result)
return result
}
}
struct Whatever: DefaultConstructible {
struct ChildData {
var foo: Int = 0
}
var name: String = ""
var age: Int = 0
var child = ChildData()
typealias Config = Configurator<Whatever>
}
let me = Whatever.Config
.name("Me")
.age(-1)
.child.foo(12)
.build()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment