idlize
219 строк · 6.1 Кб
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*/
15import {float32, int32} from "@koalaui/common"
16import {pointer} from "@koalaui/interop"
17import {RuntimeType, Tags} from "./SerializerBase";
18// import { Length } from "@arkoala/arkui"
19
20export class DeserializerBase {
21private position = 0
22private readonly buffer: ArrayBuffer
23private readonly length: int32
24private view: DataView
25private static textDecoder = new TextDecoder()
26private static customDeserializers: CustomDeserializer | undefined = undefined
27
28static registerCustomDeserializer(deserializer: CustomDeserializer) {
29let current = DeserializerBase.customDeserializers
30if (current == undefined) {
31DeserializerBase.customDeserializers = deserializer
32} else {
33while (current.next != undefined) {
34current = current.next
35}
36current.next = deserializer
37}
38}
39
40constructor(buffer: ArrayBuffer, length: int32) {
41this.buffer = buffer
42this.length = length
43this.view = new DataView(this.buffer)
44}
45
46asArray(position?: number, length?: number): Uint8Array {
47return new Uint8Array(this.buffer, position, length)
48}
49
50currentPosition(): int32 {
51return this.position
52}
53
54resetCurrentPosition(): void {
55this.position = 0
56}
57
58private checkCapacity(value: int32) {
59if (value > this.length) {
60throw new Error(`${value} is less than remaining buffer length`)
61}
62}
63
64readInt8(): int32 {
65this.checkCapacity(1)
66const value = this.view.getInt8(this.position)
67this.position += 1
68return value
69}
70
71readInt32(): int32 {
72this.checkCapacity(4)
73const value = this.view.getInt32(this.position, true)
74this.position += 4
75return value
76}
77
78readPointer(): pointer {
79this.checkCapacity(8)
80const value = this.view.getBigInt64(this.position, true)
81this.position += 8
82return value
83}
84
85readFloat32(): float32 {
86this.checkCapacity(4)
87const value = this.view.getFloat32(this.position, true)
88this.position += 4
89return value
90}
91
92readBoolean(): boolean {
93this.checkCapacity(1)
94const value = this.view.getInt8(this.position)
95this.position += 1
96return value == 1
97}
98
99readFunction(): any {
100// TODO: not exactly correct.
101const id = this.readInt32()
102return id
103}
104
105readMaterialized(): object {
106const ptr = this.readPointer()
107return { ptr: ptr }
108}
109
110readString(): string {
111const length = this.readInt32()
112this.checkCapacity(length)
113// read without null-terminated byte
114const value = DeserializerBase.textDecoder.decode(this.asArray(this.position, length - 1));
115this.position += length
116return value
117}
118
119readCustomObject(kind: string): any {
120let current = DeserializerBase.customDeserializers
121while (current) {
122if (current.supports(kind)) {
123return current.deserialize(this, kind)
124}
125current = current.next
126}
127// consume tag
128const tag = this.readInt8()
129return undefined
130}
131
132readNumber(): number | undefined {
133const tag = this.readInt8()
134switch (tag) {
135case Tags.UNDEFINED:
136return undefined;
137case Tags.INT32:
138return this.readInt32()
139case Tags.FLOAT32:
140return this.readFloat32()
141default:
142throw new Error(`Unknown number tag: ${tag}`)
143break
144}
145}
146
147readLength(): Length | undefined {
148this.checkCapacity(1)
149const valueType = this.readInt8()
150switch (valueType) {
151case RuntimeType.OBJECT:
152return {
153id: this.readInt32(),
154bundleName: "",
155moduleName: ""
156}
157case RuntimeType.STRING:
158return this.readString()
159case RuntimeType.NUMBER:
160return this.readFloat32()
161}
162return undefined
163}
164
165static lengthUnitFromInt(unit: int32): string {
166let suffix: string
167switch (unit) {
168case 0:
169suffix = "px"
170break
171case 1:
172suffix = "vp"
173break
174case 3:
175suffix = "%"
176break
177case 4:
178suffix = "lpx"
179break
180default:
181suffix = "<unknown>"
182}
183return suffix
184}
185}
186
187export abstract class CustomDeserializer {
188protected constructor(protected supported: Array<string>) {
189}
190
191supports(kind: string): boolean {
192return this.supported.includes(kind)
193}
194
195abstract deserialize(serializer: DeserializerBase, kind: string): any
196
197next: CustomDeserializer | undefined = undefined
198}
199
200class OurCustomDeserializer extends CustomDeserializer {
201constructor() {
202super(["Resource", "Pixmap"])
203}
204deserialize(deserializer: DeserializerBase, kind: string): any {
205return JSON.parse(deserializer.readString())
206}
207}
208DeserializerBase.registerCustomDeserializer(new OurCustomDeserializer())
209
210class DateDeserializer extends CustomDeserializer {
211constructor() {
212super(["Date"]);
213}
214
215deserialize(serializer: DeserializerBase, kind: string): any {
216return new Date(serializer.readString())
217}
218}
219DeserializerBase.registerCustomDeserializer(new DateDeserializer())
220