File: CanonicalLifting.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (192 lines) | stat: -rw-r--r-- 9,956 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/// A type that provides lifting of a core value to WIT values.
public protocol CanonicalLifting {
    /// A type of a core value and a type of a WIT value.
    associatedtype Operand

    /// A type of a pointer representation.
    associatedtype Pointer: Strideable

    /// Lifts a core i32 value to a WIT bool value.
    func liftBool(_ value: Operand) -> Operand
    /// Lifts a core i32 value to a WIT u8 value.
    func liftUInt8(_ value: Operand) -> Operand
    /// Lifts a core i32 value to a WIT u16 value.
    func liftUInt16(_ value: Operand) -> Operand
    /// Lifts a core i32 value to a WIT u32 value.
    func liftUInt32(_ value: Operand) -> Operand
    /// Lifts a core i64 value to a WIT u64 value.
    func liftUInt64(_ value: Operand) -> Operand
    /// Lifts a core i32 value to a WIT s8 value.
    func liftInt8(_ value: Operand) -> Operand
    /// Lifts a core i32 value to a WIT s16 value.
    func liftInt16(_ value: Operand) -> Operand
    /// Lifts a core i32 value to a WIT s32 value.
    func liftInt32(_ value: Operand) -> Operand
    /// Lifts a core i64 value to a WIT s64 value.
    func liftInt64(_ value: Operand) -> Operand
    /// Lifts a core f32 value to a WIT f32 value.
    func liftFloat32(_ value: Operand) -> Operand
    /// Lifts a core f64 value to a WIT f64 value.
    func liftFloat64(_ value: Operand) -> Operand
    /// Lifts a core i32 value to a WIT char value.
    func liftChar(_ value: Operand) -> Operand
    /// Lifts a pair of a pointer and a length, both of which are core i32 values, to a WIT string value.
    func liftString(pointer: Operand, length: Operand, encoding: String) throws -> Operand
    /// Lifts a pair of a pointer and a length, both of which are core i32 values, to a WIT list value.
    ///
    /// - Parameters:
    ///   - pointer: A pointer that contains the byte representation of the list elements.
    ///   - length: A number of elements in the list.
    ///   - element: A type of the list elements.
    ///   - loadElement: A closure that loads an element from the given pointer.
    func liftList(
        pointer: Operand, length: Operand, element: WITType,
        loadElement: (Pointer) throws -> Operand
    ) throws -> Operand
    /// Lifts lifted WIT values of the fields of a record to a WIT record value.
    func liftRecord(fields: [Operand], type: WITRecord) throws -> Operand
    /// Lifts lifted WIT values of the tuple elements to a WIT tuple value
    func liftTuple(elements: [Operand], types: [WITType]) throws -> Operand
    /// Lifts a core i32 value to a WIT enum value.
    func liftEnum(_ value: Operand, type: WITEnum) throws -> Operand
    /// Lifts core integer values to a WIT flag value.
    func liftFlags(_ value: [Operand], type: WITFlags) throws -> Operand

    /// Lifts a pair of a discriminant and payload core values to a WIT option value.
    ///
    /// - Parameters:
    ///   - discriminant: A core i32 value that represents a discriminant.
    ///   - liftPayload: A closure that lifts a payload core value to a WIT value.
    func liftOption(
        discriminant: Operand, wrapped: WITType, liftPayload: () throws -> Operand
    ) throws -> Operand

    /// Lifts a pair of a discriminant and payload core values to a WIT result value.
    ///
    /// - Parameters:
    ///   - discriminant: A core i32 value that represents a discriminant.
    ///   - liftPayload: A closure that lifts a payload core value to a WIT value.
    ///                  It takes a boolean value that indicates whether the payload is an error or not.
    func liftResult(
        discriminant: Operand, ok: WITType?, error: WITType?, liftPayload: (_ isError: Bool) throws -> Operand?
    ) throws -> Operand

    /// Lifts a pair of a discriminant and payload core values to a WIT variant value.
    ///
    /// - Parameters:
    ///   - discriminant: A core i32 value that represents a discriminant.
    ///   - liftPayload: A closure that lifts a payload core value to a WIT value.
    ///                  It takes a case index of the variant to be lifted.
    func liftVariant(
        discriminant: Operand, type: WITVariant, liftPayload: (Int) throws -> Operand?
    ) throws -> Operand
}

extension CanonicalABI {
    /// Performs ["Flat Lifting"][cabi_flat_lifting] defined in the Canonical ABI.
    /// It recursively lifts a core value to a WIT value.
    ///
    /// [cabi_flat_lifting]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md#flat-lifting
    public static func lift<Lifting: CanonicalLifting, Loading: CanonicalLoading>(
        type: WITType,
        coreValues: inout some IteratorProtocol<Lifting.Operand>,
        lifting: inout Lifting,
        loading: inout Loading
    ) throws -> Lifting.Operand where Lifting.Operand == Loading.Operand, Lifting.Pointer == Loading.Pointer {
        switch type {
        case .bool: return lifting.liftBool(coreValues.next()!)
        case .u8: return lifting.liftUInt8(coreValues.next()!)
        case .u16: return lifting.liftUInt16(coreValues.next()!)
        case .u32: return lifting.liftUInt32(coreValues.next()!)
        case .u64: return lifting.liftUInt64(coreValues.next()!)
        case .s8: return lifting.liftInt8(coreValues.next()!)
        case .s16: return lifting.liftInt16(coreValues.next()!)
        case .s32: return lifting.liftInt32(coreValues.next()!)
        case .s64: return lifting.liftInt64(coreValues.next()!)
        case .float32: return lifting.liftFloat32(coreValues.next()!)
        case .float64: return lifting.liftFloat64(coreValues.next()!)
        case .char: return lifting.liftChar(coreValues.next()!)
        case .string:
            return try lifting.liftString(
                pointer: coreValues.next()!,
                length: coreValues.next()!,
                encoding: "utf8"
            )
        case .list(let element):
            return try liftList(
                pointer: coreValues.next()!, length: coreValues.next()!,
                element: element, lifting: &lifting, loading: &loading
            )
        case .handleOwn, .handleBorrow:
            fatalError("TODO: resource type is not supported yet")
        case .record(let record):
            let fields = try record.fields.map { field in
                try lift(type: field.type, coreValues: &coreValues, lifting: &lifting, loading: &loading)
            }
            return try lifting.liftRecord(fields: fields, type: record)
        case .tuple(let types):
            let elements = try types.map { type in
                try lift(type: type, coreValues: &coreValues, lifting: &lifting, loading: &loading)
            }
            return try lifting.liftTuple(elements: elements, types: types)
        case .enum(let enumType):
            return try lifting.liftEnum(coreValues.next()!, type: enumType)
        case .flags(let flags):
            let numberOfI32 = CanonicalABI.numberOfInt32(flagsCount: flags.flags.count)
            let rawValues = (0..<numberOfI32).map { _ in coreValues.next()! }
            return try lifting.liftFlags(rawValues, type: flags)
        case .option(let wrapped):
            let discriminant = coreValues.next()!
            return try lifting.liftOption(
                discriminant: discriminant, wrapped: wrapped,
                liftPayload: {
                    try lift(type: wrapped, coreValues: &coreValues, lifting: &lifting, loading: &loading)
                }
            )
        case .result(let ok, let error):
            let discriminant = coreValues.next()!
            let unionPayloadTypes = CanonicalABI.flattenVariantPayload(variants: [ok, error])
            // Collect all the payload values here so that we can consume them multiple times.
            let unionPayloadValues = unionPayloadTypes.indices.map { _ in coreValues.next()! }
            return try lifting.liftResult(
                discriminant: discriminant, ok: ok, error: error,
                liftPayload: { isError in
                    guard let type = isError ? error : ok else { return nil }
                    var tmpIterator = unionPayloadValues.makeIterator()
                    return try lift(type: type, coreValues: &tmpIterator, lifting: &lifting, loading: &loading)
                }
            )
        case .variant(let variant):
            let discriminant = coreValues.next()!
            let unionPayloadTypes = CanonicalABI.flattenVariantPayload(variants: variant.cases.map(\.type))
            // Collect all the payload values here so that we can consume them multiple times.
            let unionPayloadValues = unionPayloadTypes.indices.map { _ in coreValues.next()! }
            return try lifting.liftVariant(
                discriminant: discriminant, type: variant,
                liftPayload: { caseIndex in
                    let variantCase = variant.cases[caseIndex]
                    guard let payloadType = variantCase.type else { return nil }
                    var tmpIterator = unionPayloadValues.makeIterator()
                    return try lift(type: payloadType, coreValues: &tmpIterator, lifting: &lifting, loading: &loading)
                })
        default:
            fatalError("TODO: lifting \"\(type)\" is unimplemented")
        }
    }

    static func liftList<Lifting: CanonicalLifting, Loading: CanonicalLoading>(
        pointer: Lifting.Operand, length: Lifting.Operand,
        element: WITType,
        lifting: inout Lifting, loading: inout Loading
    ) throws -> Lifting.Operand where Lifting.Operand == Loading.Operand, Lifting.Pointer == Loading.Pointer {
        try lifting.liftList(
            pointer: pointer, length: length, element: element,
            loadElement: { elementPtr in
                return try CanonicalABI.load(
                    loading: &loading, lifting: &lifting,
                    type: element, pointer: elementPtr
                )
            }
        )
    }
}