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 { CustomTextEncoder, CustomTextDecoder, int32 } from "@koalaui/common" 17 18import { KPointer } from "../../interop/InteropTypes" 19import { Wrapper } from "../../interop/Wrapper" 20import { Access, isRead, isWrite, Exec, TypedArray, ExecWithLength } from "../../interop/arrays" 21 22const encoder = new CustomTextEncoder() 23const decoder = new CustomTextDecoder() 24 25export function decodeToString(array: Uint8Array): string { 26 return decoder.decode(array) 27} 28 29export function encodeToData(string: string): Uint8Array { 30 return encoder.encode(string, false) 31} 32 33type Heap = { readonly buffer: ArrayBuffer } 34 35// TODO actually memory allocation primitives are defined for a specific intance instance, 36// refactor me 37declare const _heaps: { 38 HEAP8(): Heap; 39 HEAP16(): Heap; 40 HEAP32(): Heap; 41 HEAPU8(): Heap; 42 HEAPU16(): Heap; 43 HEAPU32(): Heap; 44 HEAPF32(): Heap; 45 HEAPF64(): Heap; 46} 47declare function _malloc(size: number): number; 48declare function _free(ptr: number): void; 49 50const nullptr: number = 0 51 52// with string as array of utf8 data headed by length 53export function withString<R>(data: string | undefined, exec: Exec<number, R>): R { 54 if (data === undefined) return exec(nullptr) 55 56 let array = encoder.encode(data, true) 57 return withUint8Array(array, Access.READ, exec) 58} 59 60export function withStringArray<R>(strings: Array<string> | undefined, exec: Exec<number, R>): R { 61 if (strings === undefined || strings.length === 0) { 62 return exec(nullptr) 63 } 64 65 let array = encoder.encodeArray(strings) 66 return withUint8Array(array, Access.READ, exec) 67} 68 69function withArray<C extends TypedArray, R>( 70 data: C | undefined, 71 access: Access, 72 exec: ExecWithLength<number, R>, 73 bytesPerElement: int32, 74 ctor: (ptr: number, length: number) => C 75): R { 76 if (data === undefined || data.length === 0) { 77 return exec(nullptr, 0) 78 } 79 80 let ptr = _malloc(data.length * bytesPerElement) 81 let wasmArray = ctor(ptr, data.length) 82 83 if (isRead(access)) { 84 wasmArray.set(data) 85 } 86 87 let result = exec(ptr, data.length) 88 89 if (isWrite(access)) { 90 data.set(wasmArray) 91 } 92 93 _free(ptr) 94 95 return result 96} 97 98export function withPtrArray<R>(data: Uint32Array, access: Access, exec: ExecWithLength<number, R>) { 99 return withArray(data as Uint32Array, access, exec, Uint32Array.BYTES_PER_ELEMENT, (ptr: number, length: number) => { 100 return new Uint32Array(_heaps.HEAPU8().buffer, ptr, length) 101 }) 102} 103 104export function toPtrArray<T extends Wrapper>(data: Array<T | undefined> | undefined): Uint32Array { 105 if (data === undefined || data.length === 0) { 106 return new Uint32Array(0) 107 } 108 const array = new Uint32Array(data.length) 109 for (let i = 0; i < data.length; i++) { 110 array[i] = data[i]?.ptr as number 111 } 112 return array 113} 114 115export function fromPtrArray<T extends Wrapper>(array: Uint32Array, factory: (ptr: KPointer) => T) : Array<T | undefined> { 116 const result = new Array<T|undefined>(array.length) 117 for (let i = 0; i < array.length; i++) { 118 let v = array[i] 119 if (v == 0) { 120 result[i] = undefined 121 } else { 122 result[i] = factory(v) 123 } 124 } 125 return result 126} 127 128export function withUint8Array<T>(data: Uint8Array | undefined, access: Access, exec: ExecWithLength<number, T>) { 129 return withArray(data, access, exec, Uint8Array.BYTES_PER_ELEMENT, (ptr: number, length: number) => { 130 return new Uint8Array(_heaps.HEAPU8().buffer, ptr, length) 131 }) 132} 133export function withInt8Array<T>(data: Int8Array | undefined, access: Access, exec: ExecWithLength<number, T>) { 134 return withArray(data, access, exec, Int8Array.BYTES_PER_ELEMENT, (ptr: number, length: number) => { 135 return new Int8Array(_heaps.HEAPU8().buffer, ptr, length) 136 }) 137} 138export function withUint16Array<T>(data: Uint16Array | undefined, access: Access, exec: ExecWithLength<number, T>) { 139 return withArray(data, access, exec, Uint16Array.BYTES_PER_ELEMENT, (ptr: number, length: number) => { 140 return new Uint16Array(_heaps.HEAPU8().buffer, ptr, length) 141 }) 142} 143export function withInt16Array<T>(data: Int16Array | undefined, access: Access, exec: ExecWithLength<number, T>) { 144 return withArray(data, access, exec, Int16Array.BYTES_PER_ELEMENT, (ptr: number, length: number) => { 145 return new Int16Array(_heaps.HEAPU8().buffer, ptr, length) 146 }) 147} 148export function withUint32Array<T>(data: Uint32Array | undefined, access: Access, exec: ExecWithLength<number, T>) { 149 return withArray(data, access, exec, Uint32Array.BYTES_PER_ELEMENT, (ptr: number, length: number) => { 150 return new Uint32Array(_heaps.HEAPU8().buffer, ptr, length) 151 }) 152} 153export function withInt32Array<T>(data: Int32Array | undefined, access: Access, exec: ExecWithLength<number, T>) { 154 return withArray(data, access, exec, Int32Array.BYTES_PER_ELEMENT, (ptr: number, length: number) => { 155 return new Int32Array(_heaps.HEAPU8().buffer, ptr, length) 156 }) 157} 158export function withFloat32Array<T>(data: Float32Array | undefined, access: Access, exec: ExecWithLength<number, T>) { 159 return withArray(data, access, exec, Float32Array.BYTES_PER_ELEMENT, (ptr: number, length: number) => { 160 return new Float32Array(_heaps.HEAPU8().buffer, ptr, length) 161 }) 162} 163export function withFloat64Array<T>(data: Float64Array | undefined, access: Access, exec: ExecWithLength<number, T>) { 164 return withArray(data, access, exec, Float64Array.BYTES_PER_ELEMENT, (ptr: number, length: number) => { 165 return new Float64Array(_heaps.HEAPU8().buffer, ptr, length) 166 }) 167} 168 169export function wasmHeap(): ArrayBuffer { 170 return _heaps.HEAP32().buffer 171} 172