Last active
April 12, 2018 01:11
-
-
Save milseman/b86e7ec89fbbd2cf1f189fcf75be8a54 to your computer and use it in GitHub Desktop.
ExpressiblyByStringInterpolation Alternative Formulation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
protocol ESI { | |
// Interpolate a segment | |
mutating func addSegment<T>(_ t: T) | |
// Interpolate a literal | |
mutating func addLiteral(_ s: String) | |
// Compiler will produce closure to pass to this init. Closure will consist | |
// of calls to writeSegment and writeLiteral | |
init(performingInterpolation: (inout Self) -> ()) | |
// Maybe: compiler can also give the literals and number of segments to the | |
// conformer so they can estimate a reserve capacity? Or just combined literal | |
// lengths? Too much? | |
init( | |
numSegments: Int, | |
literals: String..., | |
performingInterpolation: (inout Self) -> () | |
) | |
} | |
extension ESI { | |
init( | |
numSegments: Int, | |
literals: String..., | |
performingInterpolation f: (inout Self) -> () | |
) { | |
self.init(performingInterpolation: f) | |
} | |
} | |
extension ESI where Self: TextOutputStream { | |
mutating func addSegment<T>(_ t: T) { | |
print(t, terminator: "", to: &self) | |
} | |
mutating func addLiteral(_ s: String) { | |
write(s) | |
} | |
} | |
struct MyESI { | |
var value: String = "" | |
} | |
extension MyESI: TextOutputStream { | |
mutating func write(_ string: String) { | |
value.append(string) | |
} | |
} | |
extension MyESI: ESI { | |
// Let's say MyESI has some setup work it wants to do | |
init(forInterpolation:()) { /*...*/ } | |
// Let's say we have tear-down work we want to do | |
mutating func finalize() { /*...*/ } | |
init(performingInterpolation f: (inout MyESI) -> ()) { | |
var ret = MyESI(forInterpolation: ()) | |
f(&ret) | |
ret.finalize() | |
self = ret | |
} | |
} | |
// Demonstrates what the compiler would produce for arbitary segments | |
func exampleCompilerOutput<T, U, V>(_ t: T, _ u: U, _ v: V) -> MyESI { | |
// return "abc\(t)def\(u)ghi\(v)jkl" as ESI | |
return MyESI(performingInterpolation: { (esi: inout MyESI) -> () in | |
esi.addLiteral("abc") | |
esi.addSegment(t) | |
esi.addLiteral("def") | |
esi.addSegment(u) | |
esi.addLiteral("ghi") | |
esi.addSegment(v) | |
esi.addLiteral("jkl") | |
}) | |
// Alternatively: as above, but also passing in num segments and literals | |
} | |
print(exampleCompilerOutput(1,2.0,3).value) // abc1def2.0ghi3jkl | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment