1/* 2 * Copyright (c) 2022-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 { KUint8ArrayPtr } from "./InteropTypes" 17import { int32 } from "@koalaui/common" 18 19export type CallbackType = (args: KUint8ArrayPtr, length: int32) => int32 20 21class CallbackRecord { 22 public readonly callback: CallbackType 23 public readonly autoDisposable: boolean 24 25 constructor( 26 callback: CallbackType, 27 autoDisposable: boolean 28 ) { 29 this.callback = callback 30 this.autoDisposable = autoDisposable 31 } 32} 33 34class CallbackRegistry { 35 36 static INSTANCE = new CallbackRegistry() 37 38 private callbacks = new Map<int32, CallbackRecord>() 39 private id = 1024 40 41 constructor() { 42 this.callbacks.set(0, new CallbackRecord( 43 (args: KUint8ArrayPtr, length: int32): int32 => { 44 console.log(`Callback 0 called with args = ${args} and length = ${length}`) 45 throw new Error(`Null callback called`) 46 }, false) 47 ) 48 } 49 50 wrap(callback: CallbackType, autoDisposable: boolean): int32 { 51 const id = this.id++ 52 this.callbacks.set(id, new CallbackRecord(callback, autoDisposable)) 53 return id 54 } 55 56 wrapSystem(id: int32, callback: CallbackType, autoDisposable: boolean): int32 { 57 this.callbacks.set(id, new CallbackRecord(callback, autoDisposable)) 58 return id 59 } 60 61 call(id: int32, args: KUint8ArrayPtr, length: int32): int32 { 62 const record = this.callbacks.get(id) 63 if (!record) { 64 console.log(`Callback ${id} is not known`) 65 throw new Error(`Disposed or unwrapped callback called (id = ${id})`) 66 } 67 if (record.autoDisposable) { 68 this.dispose(id) 69 } 70 return record.callback(args, length) 71 } 72 73 dispose(id: int32) { 74 this.callbacks.delete(id) 75 } 76} 77 78export function wrapCallback(callback: CallbackType, autoDisposable: boolean = true): int32 { 79 return CallbackRegistry.INSTANCE.wrap(callback, autoDisposable) 80} 81 82export function wrapSystemCallback(id:int32, callback: CallbackType): int32 { 83 return CallbackRegistry.INSTANCE.wrapSystem(id, callback, false) 84} 85 86export function disposeCallback(id: int32) { 87 CallbackRegistry.INSTANCE.dispose(id) 88} 89 90export function callCallback(id: int32, args: KUint8ArrayPtr, length: int32): int32 { 91 return CallbackRegistry.INSTANCE.call(id, args, length) 92} 93