• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { finalizerRegister, finalizerUnregister, Thunk } from "@koalaui/common"
17import { InteropNativeModule } from "./InteropNativeModule"
18import { pointer, nullptr } from "./InteropTypes"
19
20class NativeThunk implements Thunk {
21    finalizer: pointer
22    obj: pointer
23    name: string|undefined
24
25    constructor(obj: pointer, finalizer: pointer, name?: string) {
26        this.finalizer = finalizer
27        this.obj = obj
28        this.name = name
29    }
30
31    clean() {
32        if (this.obj != nullptr) {
33            this.destroyNative(this.obj, this.finalizer)
34        }
35        this.obj = nullptr
36    }
37
38    destroyNative(ptr: pointer, finalizer: pointer): void {
39        InteropNativeModule._InvokeFinalizer(ptr, finalizer)
40    }
41}
42
43/**
44 * Class with the custom finalizer, usually used to release a native peer.
45 * Do not use directly, only via subclasses.
46 */
47export class Finalizable {
48    ptr: pointer
49    finalizer: pointer
50    cleaner: NativeThunk|undefined = undefined
51    managed: boolean
52    constructor(ptr: pointer, finalizer: pointer, managed: boolean = true) {
53        this.ptr = ptr
54        this.finalizer = finalizer
55        this.managed = managed
56        const handle = undefined
57
58        if (this.managed) {
59            if (this.ptr == nullptr) throw new Error("Can't have nullptr ptr ${}")
60            if (this.finalizer == nullptr) throw new Error("Managed finalizer is 0")
61
62            const thunk = new NativeThunk(ptr, finalizer, handle)
63            finalizerRegister(this, thunk)
64            this.cleaner = thunk
65        }
66    }
67
68    close() {
69        if (this.ptr == nullptr) {
70            throw new Error(`Closing a closed object: ` + this.toString())
71        } else if (this.cleaner == undefined) {
72            throw new Error(`No thunk assigned to ` + this.toString())
73        } else {
74            finalizerUnregister(this)
75            this.cleaner!.clean()
76            this.cleaner = undefined
77            this.ptr = nullptr
78        }
79    }
80
81    release(): pointer {
82        finalizerUnregister(this)
83        if (this.cleaner)
84            this.cleaner!.obj = nullptr
85        let result = this.ptr
86        this.ptr = nullptr
87        return result
88    }
89
90    resetPeer(pointer: pointer) {
91        if (this.managed) throw new Error("Can only reset peer for an unmanaged object")
92        this.ptr = pointer
93    }
94
95    use<R>(body: (value: Finalizable) => R): R {
96        let result = body(this)
97        this.close()
98        return result
99    }
100}
101