+
+extension OneOf: Printer where Parsers: Printer {
+ func print(_ output: Parsers.Output, to input: inout Parsers.Input) throws {
+ try self.parsers.print(output, to: &input)
+ }
+}
+
+extension Parsers.OneOf2: Printer where P0: Printer, P1: Printer {
+ func print(_ output: P0.Output, to input: inout P0.Input) throws {
+ let original = input
+ do {
+ try self.p1.print(output, to: &input)
+ } catch {
+ input = original
+ try self.p0.print(output, to: &input)
+ }
+ }
+}
+
+extension Parsers.OneOf3: Printer where P0: Printer, P1: Printer, P2: Printer {
+ func print(_ output: P0.Output, to input: inout P0.Input) throws {
+ let original = input
+ do {
+ try self.p2.print(output, to: &input)
+ } catch {
+ input = original
+ do {
+ try self.p1.print(output, to: &input)
+ } catch {
+ input = original
+ try self.p0.print(output, to: &input)
+ }
+ }
+ }
+}
+
+extension Skip: Printer where Parsers: Printer, Parsers.Output == Void {
+ func print(
+ _ output: (),
+ to input: inout Parsers.Input
+ ) throws {
+ try self.parsers.print((), to: &input)
+ }
+}
+
+extension Parsers.ZipVV: Printer where P0: Printer, P1: Printer {
+ func print(_ output: (), to input: inout P0.Input) throws {
+ try self.p0.print((), to: &input)
+ try self.p1.print((), to: &input)
+ }
+}
+
+extension Parsers.IntParser: Printer where Input: AppendableCollection {
+ func print(_ output: Output, to input: inout Input) {
+// var substring = Substring(input)
+// substring.append(contentsOf: String(output))
+// input = substring.utf8
+ input.append(contentsOf: String(output).utf8)
+ }
+}
+
+extension FromUTF8View: Printer where UTF8Parser: Printer {
+ func print(
+ _ output: UTF8Parser.Output,
+ to input: inout Input
+ ) throws {
+ var utf8 = self.toUTF8(input)
+ defer { input = self.fromUTF8(utf8) }
+ try self.utf8Parser.print(output, to: &utf8)
+ }
+}
+
+extension Parsers.BoolParser: Printer where Input: AppendableCollection {
+ func print(
+ _ output: Bool,
+ to input: inout Input
+ ) throws {
+ input.append(contentsOf: String(output).utf8)
+ }
+}
+
+extension Parsers.ZipOVOVO: Printer
+where
+ P0: Printer,
+ P1: Printer,
+ P2: Printer,
+ P3: Printer,
+ P4: Printer
+{
+ func print(_ output: (P0.Output, P2.Output, P4.Output), to input: inout P0.Input) throws {
+ try self.p0.print(output.0, to: &input)
+ try self.p1.print((), to: &input)
+ try self.p2.print(output.1, to: &input)
+ try self.p3.print((), to: &input)
+ try self.p4.print(output.2, to: &input)
+ }
+}
+
+extension Many: Printer
+where
+ Element: Printer,
+ Separator: Printer,
+ Separator.Output == Void,
+ Result == [Element.Output]
+{
+ func print(_ output: [Element.Output], to input: inout Element.Input) throws {
+ var firstElement = true
+ for elementOutput in output {
+ defer { firstElement = false }
+ if !firstElement {
+ try self.separator.print((), to: &input)
+ }
+ try self.element.print(elementOutput, to: &input)
+ }
+ }
+}
+
+try Parse
+{
+ "Hello "
+ FromUTF8View { Int.parser() }
+ "!"
+}
+.parse("Hello 42!")
+
+input = ""
+try Parse { "Hello "; Int.parser(); "!" }
+.print(42, to: &input)
+input
+
+//Skip { Prefix { $0 != "," } }.print(<#T##output: ()##()#>, to: &<#T##_#>)
+
+
+// f: (A) -> B
+
+// parse: (inout Input) throws -> Output
+// print: (Output, inout Input) throws -> Void
+
+// .map { Role.admin }
+
+extension Parsers.Map: Printer where
+ Upstream: Printer,
+ Upstream.Output == Void,
+ NewOutput: Equatable
+{
+ func print(_ output: NewOutput, to input: inout Upstream.Input) throws {
+ guard self.transform(()) == output
+ else {
+ throw PrintingError()
+ }
+ try self.upstream.print((), to: &input)
+ }
+}
+
+typealias ParserPrinter = Parser & Printer
+
+struct Conversion {
+ let apply: (A) throws -> B
+ let unapply: (B) throws -> A
+}
+
+extension Conversion where A == Substring, B == String {
+ static let string = Self(
+ apply: { String($0) },
+ unapply: { Substring($0) }
+ )
+}
+
+extension Parser where Self: Printer {
+ func map