diff --git a/Sources/Parsing/Builders/ParserBuilder.swift b/Sources/Parsing/Builders/ParserBuilder.swift index d72c0cc38c..d26b6f490b 100644 --- a/Sources/Parsing/Builders/ParserBuilder.swift +++ b/Sources/Parsing/Builders/ParserBuilder.swift @@ -272,13 +272,23 @@ extension ParserBuilder.Take2 { extension ParserBuilder.Take2.Map: ParserPrinter where P0: ParserPrinter, P1: ParserPrinter { public func print(_ output: NewOutput, into input: inout P0.Input) throws { - guard let tuple = output as? (P0.Output, P1.Output) else { + guard canBitCast(NewOutput.self, to: (P0.Output, P1.Output).self) + else { throw ParsingError.failed( summary: "Could not convert output to required tuple type", from: output, to: input ) } - try upstream.print(tuple, into: &input) + try upstream.print( + unsafeBitCast(output, to: (P0.Output, P1.Output).self), + into: &input + ) } } + +private func canBitCast(_ type: T.Type, to otherType: U.Type) -> Bool { + MemoryLayout.size == MemoryLayout.size + && MemoryLayout.alignment == MemoryLayout.alignment + && MemoryLayout.stride == MemoryLayout.stride +} diff --git a/Tests/ParsingTests/ParserBuilderTests.swift b/Tests/ParsingTests/ParserBuilderTests.swift index 4cbb5b6012..d8442c103e 100644 --- a/Tests/ParsingTests/ParserBuilderTests.swift +++ b/Tests/ParsingTests/ParserBuilderTests.swift @@ -160,4 +160,46 @@ final class ParserBuilderTests: XCTestCase { } XCTAssertEqual(input, " Blob"[...]) } + + func testNestedPrint() throws { + let p1 = ParsePrint(input: Substring.self) { + Digits() + "," + Digits() + } + let p2 = ParsePrint(input: Substring.self) { + Digits() + "," + Digits() + } + let p3 = ParsePrint { + p1 + "," + p2 + } + var input = ""[...] + try p3.print((1, 2, (3, 4)), into: &input) + XCTAssertEqual(input, "1,2,3,4") + } + + func testNestedPrint_differentLayouts() throws { + let p1 = ParsePrint(input: Substring.self) { + Int32.parser() + "," + Int8.parser() + } + let p2 = ParsePrint(input: Substring.self) { + Int8.parser() + "," + Int32.parser() + } + let p3 = ParsePrint { + p1 + "," + p2 + } + var input = ""[...] + try p3.print((1, 2, (3, 4)), into: &input) + XCTAssertEqual(input, "1,2,3,4") + } }