idlize
207 строк · 6.0 Кб
1/*
2* Copyright (c) 2024 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 { int32, float32 } from "@koalaui/common"
17
18export type NodePointer = pointer // todo: move to NativeModule
19
20export type KStringPtr = int32 | string | null
21export type KStringPtrArray = int32 | Uint8Array | null
22export type KUint8ArrayPtr = int32 | Uint8Array | null
23export type KInt32ArrayPtr = int32 | Int32Array | null
24export type KFloat32ArrayPtr = int32 | Float32Array | null
25export type KInt = int32
26export type KUInt = int32
27export type KBoolean = int32
28export type KFloat = float32
29export type KPointer = number | bigint
30export type pointer = KPointer
31export type KNativePointer = KPointer
32
33export type TypedArray = // todo: move to interop-smth
34Uint8Array
35| Int8Array
36| Uint16Array
37| Int16Array
38| Uint32Array
39| Int32Array
40| Float32Array
41| Float64Array
42
43export function decodeToString(array: Uint8Array): string {
44return decoder.decode(array)
45}
46
47export function isNullPtr(value: KPointer): boolean {
48return value === nullptr
49}
50
51export function className(object?: Object): string {
52return object?.constructor.name ?? "<null>"
53}
54
55export function ptrToString(ptr: KPointer) {
56return `0x${ptr!.toString(16).padStart(8, "0")}`
57}
58
59interface WithStreamOption {
60stream?: boolean | undefined;
61}
62
63interface SystemTextDecoder {
64decode(
65input?: ArrayBuffer,
66options?: WithStreamOption
67): string;
68}
69export class CustomTextDecoder {
70static cpArrayMaxSize = 128
71constructor(decoder?: SystemTextDecoder) {
72this.decoder = decoder ?? new TextDecoder()
73}
74
75private readonly decoder: SystemTextDecoder
76
77decode(input: Uint8Array): string {
78if (this.decoder !== undefined) {
79return this.decoder!.decode(input)
80}
81const cpSize = Math.min(CustomTextDecoder.cpArrayMaxSize, input.length)
82let codePoints = new Int32Array(cpSize)
83let cpIndex = 0;
84let index = 0
85let result = ""
86while (index < input.length) {
87let elem = input[index]
88let lead = elem & 0xff
89let count = 0
90let value = 0
91if (lead < 0x80) {
92count = 1
93value = elem
94} else if ((lead >> 5) == 0x6) {
95value = ((elem << 6) & 0x7ff) + (input[index + 1] & 0x3f)
96count = 2
97} else if ((lead >> 4) == 0xe) {
98value = ((elem << 12) & 0xffff) + ((input[index + 1] << 6) & 0xfff) +
99(input[index + 2] & 0x3f)
100count = 3
101} else if ((lead >> 3) == 0x1e) {
102value = ((elem << 18) & 0x1fffff) + ((input[index + 1] << 12) & 0x3ffff) +
103((input[index + 2] << 6) & 0xfff) + (input[index + 3] & 0x3f)
104count = 4
105}
106codePoints[cpIndex++] = value
107if (cpIndex == cpSize) {
108cpIndex = 0
109result += String.fromCodePoint(...codePoints)
110}
111index += count
112}
113if (cpIndex > 0) {
114result += String.fromCodePoint(...codePoints.slice(0, cpIndex))
115}
116return result
117}
118}
119
120const decoder = new CustomTextDecoder()
121
122export class Wrapper {
123protected ptr: KPointer
124constructor(ptr: KPointer) {
125if (ptr == null)
126throw new Error(`Init <${className(this)}> with null native peer`)
127this.ptr = ptr
128}
129toString(): string {
130return `[native object <${className(this)}> at ${ptrToString(this.ptr)}]`
131}
132}
133
134export abstract class NativeStringBase extends Wrapper {
135constructor(ptr: KPointer) {
136super(ptr)
137}
138
139protected abstract bytesLength(): int32
140protected abstract getData(data: Uint8Array): void
141
142toString(): string {
143let length = this.bytesLength()
144let data = new Uint8Array(length)
145this.getData(data)
146return decodeToString(data)
147}
148
149abstract close(): void
150}
151
152export const nullptr: pointer = BigInt(0)
153
154export interface PlatformDefinedData {
155nativeString(ptr: KPointer): NativeStringBase
156nativeStringArrayDecoder(ptr: KPointer): ArrayDecoder<NativeStringBase>
157callbackRegistry(): CallbackRegistry | undefined
158}
159
160let platformData: PlatformDefinedData | undefined = undefined
161
162export function providePlatformDefinedData(platformDataParam: PlatformDefinedData) {
163platformData = platformDataParam
164}
165
166export function withStringResult(ptr: KPointer): string|undefined {
167if (isNullPtr(ptr)) return undefined
168let managedString = platformData!.nativeString(ptr)
169let result = managedString?.toString()
170managedString?.close()
171return result
172}
173
174export enum Access {
175READ = 1 << 0,
176WRITE = 1 << 1,
177READWRITE = READ | WRITE
178}
179
180export type ExecWithLength<P, R> = (pointer: P, length: int32) => R
181
182function withArray<C extends TypedArray, R>(
183data: C | undefined,
184exec: ExecWithLength<C | null, R>
185): R {
186return exec(data ?? null, data?.length ?? 0)
187}
188
189export function withUint8Array<T>(data: Uint8Array | undefined, access: Access, exec: ExecWithLength<Uint8Array | null, T>) {
190return withArray(data, exec)
191}
192
193export const withByteArray = withUint8Array
194
195export abstract class ArrayDecoder<T> {
196abstract getArraySize(blob: KPointer): int32
197abstract disposeArray(blob: KPointer): void
198abstract getArrayElement(blob: KPointer, index: int32): T
199
200decode(blob: KPointer): Array<T> {
201throw new Error(`TODO`)
202}
203}
204
205export interface CallbackRegistry {
206registerCallback(callback: any, obj: any): KPointer
207}
208