A type safe swift ResultBuilder DSL for structured directories
3.6 kB
104 lines
1extension Conversion {
2 /// A conversion from a given raw representable type's raw value to itself.
3 ///
4 /// This conversion is useful for mapping the output of a more primitive parser-printer into a
5 /// raw representable value.
6 ///
7 /// For example, you may have a raw representable type that wraps a more primitive type for the
8 /// purpose of strengthening type requirements in your APIs. One example is an identifier type
9 /// that wraps an integer:
10 ///
11 /// ```swift
12 /// struct UserID: RawRepresentable {
13 /// var rawValue: Int
14 /// }
15 /// ```
16 ///
17 /// You can transform an `Int` parser into a `UserID` parser by invoking ``Parser/map(_:)-18m9d``
18 /// with this conversion:
19 ///
20 /// ```swift
21 /// let userID = Int.parser().map(.representing(UserID.self))
22 /// ```
23 ///
24 /// See ``representing(_:)-swift.method`` for a fluent version of this interface that transforms
25 /// an existing conversion. This fluent API is particularly useful when mapping string raw values
26 /// directly from parsers of substrings and UTF-8 views, which require first transforming the
27 /// parsed substring or UTF-8 view into a string via the ``string-swift.type.property-9owth`` and
28 /// ``string-swift.type.property-3u2b5`` conversions.
29 ///
30 /// ```swift
31 /// struct EmailAddress: RawRepresentable {
32 /// var rawValue: String
33 /// }
34 ///
35 /// let emailAddress = Parse(.string.representing(EmailAddress.self)) {
36 /// Consumed {
37 /// PrefixUpTo("@")
38 /// "@"
39 /// Rest()
40 /// }
41 /// }
42 /// ```
43 ///
44 /// - Parameter type: A type that conforms to `RawRepresentable`.
45 /// - Returns: A conversion from a raw value to the given type.
46 @inlinable
47 public static func representing<NewOutput>(
48 _ type: NewOutput.Type
49 ) -> Self where Self == Conversions.FromRawValue<NewOutput> {
50 .init()
51 }
52
53 /// Transforms this conversion to a raw value into a conversion to the given raw representable
54 /// type.
55 ///
56 /// A fluent version of ``Conversion/representing(_:)-swift.type.method``. Equivalent to calling
57 /// ``map(_:)`` with ``Conversion/representing(_:)-swift.type.method``:
58 ///
59 /// ```swift
60 /// stringConversion.representing(EmailAddress.self)
61 /// // =
62 /// stringConversion.map(.representing(EmailAddress.self)
63 /// ```
64 ///
65 /// - Parameter type: A type that conforms to `RawRepresentable`.
66 /// - Returns: A conversion from a raw value to the given type.
67 @inlinable
68 public func representing<NewOutput>(
69 _ type: NewOutput.Type
70 ) -> Conversions.Map<Self, Conversions.FromRawValue<NewOutput>> {
71 self.map(.representing(NewOutput.self))
72 }
73}
74
75extension Conversions {
76 /// A conversion from a raw value to a raw representable type.
77 ///
78 /// You will not typically need to interact with this type directly. Instead you will usually use
79 /// the ``Conversion/representing(_:)-swift.type.method`` operation, which constructs this type.
80 public struct FromRawValue<Output: RawRepresentable>: Conversion {
81 @inlinable
82 public init() {}
83
84 @inlinable
85 public func apply(_ input: Output.RawValue) throws -> Output {
86 guard let output = Output(rawValue: input)
87 else {
88 var debugDescription = ""
89 debugPrint(input, to: &debugDescription)
90 throw ConvertingError(
91 """
92 representing: Failed to convert \(debugDescription) to \(Output.self).
93 """
94 )
95 }
96 return output
97 }
98
99 @inlinable
100 public func unapply(_ output: Output) -> Output.RawValue {
101 output.rawValue
102 }
103 }
104}