summaryrefslogtreecommitdiffstats
path: root/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/CallbackInterfaceRuntime.swift
blob: 9ae62d1667e983efd4a2a886a813ad93eda039a5 (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
fileprivate extension NSLock {
    func withLock<T>(f: () throws -> T) rethrows -> T {
        self.lock()
        defer { self.unlock() }
        return try f()
    }
}

fileprivate typealias UniFFICallbackHandle = UInt64
fileprivate class UniFFICallbackHandleMap<T> {
    private var leftMap: [UniFFICallbackHandle: T] = [:]
    private var counter: [UniFFICallbackHandle: UInt64] = [:]
    private var rightMap: [ObjectIdentifier: UniFFICallbackHandle] = [:]

    private let lock = NSLock()
    private var currentHandle: UniFFICallbackHandle = 0
    private let stride: UniFFICallbackHandle = 1

    func insert(obj: T) -> UniFFICallbackHandle {
        lock.withLock {
            let id = ObjectIdentifier(obj as AnyObject)
            let handle = rightMap[id] ?? {
                currentHandle += stride
                let handle = currentHandle
                leftMap[handle] = obj
                rightMap[id] = handle
                return handle
            }()
            counter[handle] = (counter[handle] ?? 0) + 1
            return handle
        }
    }

    func get(handle: UniFFICallbackHandle) -> T? {
        lock.withLock {
            leftMap[handle]
        }
    }

    func delete(handle: UniFFICallbackHandle) {
        remove(handle: handle)
    }

    @discardableResult
    func remove(handle: UniFFICallbackHandle) -> T? {
        lock.withLock {
            defer { counter[handle] = (counter[handle] ?? 1) - 1 }
            guard counter[handle] == 1 else { return leftMap[handle] }
            let obj = leftMap.removeValue(forKey: handle)
            if let obj = obj {
                rightMap.removeValue(forKey: ObjectIdentifier(obj as AnyObject))
            }
            return obj
        }
    }
}

// Magic number for the Rust proxy to call using the same mechanism as every other method,
// to free the callback once it's dropped by Rust.
private let IDX_CALLBACK_FREE: Int32 = 0
// Callback return codes
private let UNIFFI_CALLBACK_SUCCESS: Int32 = 0
private let UNIFFI_CALLBACK_ERROR: Int32 = 1
private let UNIFFI_CALLBACK_UNEXPECTED_ERROR: Int32 = 2