Skip to content

Commit 3432cb8

Browse files
authored
Attempt to safely bitcast for printing of parameter packs (#369)
1 parent fda0226 commit 3432cb8

File tree

2 files changed

+54
-2
lines changed

2 files changed

+54
-2
lines changed

Sources/Parsing/Builders/ParserBuilder.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,13 +272,23 @@ extension ParserBuilder.Take2 {
272272
extension ParserBuilder.Take2.Map: ParserPrinter
273273
where P0: ParserPrinter, P1: ParserPrinter {
274274
public func print(_ output: NewOutput, into input: inout P0.Input) throws {
275-
guard let tuple = output as? (P0.Output, P1.Output) else {
275+
guard canBitCast(NewOutput.self, to: (P0.Output, P1.Output).self)
276+
else {
276277
throw ParsingError.failed(
277278
summary: "Could not convert output to required tuple type",
278279
from: output,
279280
to: input
280281
)
281282
}
282-
try upstream.print(tuple, into: &input)
283+
try upstream.print(
284+
unsafeBitCast(output, to: (P0.Output, P1.Output).self),
285+
into: &input
286+
)
283287
}
284288
}
289+
290+
private func canBitCast<T, U>(_ type: T.Type, to otherType: U.Type) -> Bool {
291+
MemoryLayout<T>.size == MemoryLayout<U>.size
292+
&& MemoryLayout<T>.alignment == MemoryLayout<U>.alignment
293+
&& MemoryLayout<T>.stride == MemoryLayout<U>.stride
294+
}

Tests/ParsingTests/ParserBuilderTests.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,46 @@ final class ParserBuilderTests: XCTestCase {
160160
}
161161
XCTAssertEqual(input, " Blob"[...])
162162
}
163+
164+
func testNestedPrint() throws {
165+
let p1 = ParsePrint(input: Substring.self) {
166+
Digits()
167+
","
168+
Digits()
169+
}
170+
let p2 = ParsePrint(input: Substring.self) {
171+
Digits()
172+
","
173+
Digits()
174+
}
175+
let p3 = ParsePrint {
176+
p1
177+
","
178+
p2
179+
}
180+
var input = ""[...]
181+
try p3.print((1, 2, (3, 4)), into: &input)
182+
XCTAssertEqual(input, "1,2,3,4")
183+
}
184+
185+
func testNestedPrint_differentLayouts() throws {
186+
let p1 = ParsePrint(input: Substring.self) {
187+
Int32.parser()
188+
","
189+
Int8.parser()
190+
}
191+
let p2 = ParsePrint(input: Substring.self) {
192+
Int8.parser()
193+
","
194+
Int32.parser()
195+
}
196+
let p3 = ParsePrint {
197+
p1
198+
","
199+
p2
200+
}
201+
var input = ""[...]
202+
try p3.print((1, 2, (3, 4)), into: &input)
203+
XCTAssertEqual(input, "1,2,3,4")
204+
}
163205
}

0 commit comments

Comments
 (0)