• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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