Skip to content

Commit

Permalink
Attempt to safely bitcast for printing of parameter packs (#369)
Browse files Browse the repository at this point in the history
  • Loading branch information
stephencelis authored Jan 16, 2025
1 parent fda0226 commit 3432cb8
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 2 deletions.
14 changes: 12 additions & 2 deletions Sources/Parsing/Builders/ParserBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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<T, U>(_ type: T.Type, to otherType: U.Type) -> Bool {
MemoryLayout<T>.size == MemoryLayout<U>.size
&& MemoryLayout<T>.alignment == MemoryLayout<U>.alignment
&& MemoryLayout<T>.stride == MemoryLayout<U>.stride
}
42 changes: 42 additions & 0 deletions Tests/ParsingTests/ParserBuilderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
}

0 comments on commit 3432cb8

Please sign in to comment.