summaryrefslogtreecommitdiffstats
path: root/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/ForeignExecutorTemplate.swift
blob: 167e4c75460528654fa461f04e79650122534fb8 (plain)
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
private let UNIFFI_RUST_TASK_CALLBACK_SUCCESS: Int8 = 0
private let UNIFFI_RUST_TASK_CALLBACK_CANCELLED: Int8 = 1
private let UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS: Int8 = 0
private let UNIFFI_FOREIGN_EXECUTOR_CALLBACK_CANCELED: Int8 = 1
private let UNIFFI_FOREIGN_EXECUTOR_CALLBACK_ERROR: Int8 = 2

// Encapsulates an executor that can run Rust tasks
//
// On Swift, `Task.detached` can handle this we just need to know what priority to send it.
public struct UniFfiForeignExecutor {
    var priority: TaskPriority

    public init(priority: TaskPriority) {
        self.priority = priority
    }

    public init() {
        self.priority = Task.currentPriority
    }
}

fileprivate struct FfiConverterForeignExecutor: FfiConverter {
    typealias SwiftType = UniFfiForeignExecutor
    // Rust uses a pointer to represent the FfiConverterForeignExecutor, but we only need a u8.
    // let's use `Int`, which is equivalent to `size_t`
    typealias FfiType = Int

    public static func lift(_ value: FfiType) throws -> SwiftType {
        UniFfiForeignExecutor(priority: TaskPriority(rawValue: numericCast(value)))
    }
    public static func lower(_ value: SwiftType) -> FfiType {
        numericCast(value.priority.rawValue)
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
        fatalError("FfiConverterForeignExecutor.read not implemented yet")
    }
    public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
        fatalError("FfiConverterForeignExecutor.read not implemented yet")
    }
}


fileprivate func uniffiForeignExecutorCallback(executorHandle: Int, delayMs: UInt32, rustTask: UniFfiRustTaskCallback?, taskData: UnsafeRawPointer?) -> Int8 {
    if let rustTask = rustTask {
        let executor = try! FfiConverterForeignExecutor.lift(executorHandle)
        Task.detached(priority: executor.priority) {
            if delayMs != 0 {
                let nanoseconds: UInt64 = numericCast(delayMs * 1000000)
                try! await Task.sleep(nanoseconds: nanoseconds)
            }
            rustTask(taskData, UNIFFI_RUST_TASK_CALLBACK_SUCCESS)
        }
        return UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS
    } else {
        // When rustTask is null, we should drop the foreign executor.
        // However, since its just a value type, we don't need to do anything here.
        return UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS
    }
}

fileprivate func uniffiInitForeignExecutor() {
    {%- match ci.ffi_foreign_executor_callback_set() %}
    {%- when Some with (fn) %}
    {{ fn.name() }}(uniffiForeignExecutorCallback)
    {%- when None %}
    {#- No foreign executor, we don't set anything #}
    {% endmatch %}
}