|
| 1 | +/* |
| 2 | + * Licensed to the Apache Software Foundation (ASF) under one |
| 3 | + * or more contributor license agreements. See the NOTICE file |
| 4 | + * distributed with this work for additional information |
| 5 | + * regarding copyright ownership. The ASF licenses this file |
| 6 | + * to you under the Apache License, Version 2.0 (the |
| 7 | + * "License"); you may not use this file except in compliance |
| 8 | + * with the License. You may obtain a copy of the License at |
| 9 | + * |
| 10 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | + * |
| 12 | + * Unless required by applicable law or agreed to in writing, |
| 13 | + * software distributed under the License is distributed on an |
| 14 | + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 15 | + * KIND, either express or implied. See the License for the |
| 16 | + * specific language governing permissions and limitations |
| 17 | + * under the License. |
| 18 | + */ |
| 19 | + |
| 20 | +import { |
| 21 | + ForyTypeInfoSymbol, |
| 22 | + WithForyClsInfo, |
| 23 | + Serializer, |
| 24 | + TypeId, |
| 25 | +} from "./type"; |
| 26 | +import { Gen } from "./gen"; |
| 27 | +import { Type, TypeInfo } from "./typeInfo"; |
| 28 | +import Fory from "./fory"; |
| 29 | + |
| 30 | +/* eslint-disable @typescript-eslint/no-unused-vars */ |
| 31 | +const uninitSerialize: Serializer = { |
| 32 | + fixedSize: 0, |
| 33 | + getTypeId: () => { |
| 34 | + throw new Error("uninitSerialize"); |
| 35 | + }, |
| 36 | + getUserTypeId: () => { |
| 37 | + throw new Error("uninitSerialize"); |
| 38 | + }, |
| 39 | + needToWriteRef: () => { |
| 40 | + throw new Error("uninitSerialize"); |
| 41 | + }, |
| 42 | + getHash: () => { |
| 43 | + throw new Error("uninitSerialize"); |
| 44 | + }, |
| 45 | + write: (_v: any) => { |
| 46 | + throw new Error("uninitSerialize"); |
| 47 | + }, |
| 48 | + writeRef: (_v: any) => { |
| 49 | + throw new Error("uninitSerialize"); |
| 50 | + }, |
| 51 | + writeNoRef: (_v: any) => { |
| 52 | + throw new Error("uninitSerialize"); |
| 53 | + }, |
| 54 | + writeRefOrNull: (_v: any) => { |
| 55 | + throw new Error("uninitSerialize"); |
| 56 | + }, |
| 57 | + writeTypeInfo: (_v: any) => { |
| 58 | + throw new Error("uninitSerialize"); |
| 59 | + }, |
| 60 | + read: (_fromRef: boolean) => { |
| 61 | + throw new Error("uninitSerialize"); |
| 62 | + }, |
| 63 | + readRef: () => { |
| 64 | + throw new Error("uninitSerialize"); |
| 65 | + }, |
| 66 | + readNoRef: (_fromRef: boolean) => { |
| 67 | + throw new Error("uninitSerialize"); |
| 68 | + }, |
| 69 | + readTypeInfo: () => { |
| 70 | + throw new Error("uninitSerialize"); |
| 71 | + }, |
| 72 | +}; |
| 73 | +/* eslint-enable @typescript-eslint/no-unused-vars */ |
| 74 | + |
| 75 | +export default class ClassResolver { |
| 76 | + private internalSerializer: Serializer[] = new Array(300); |
| 77 | + private customSerializer: Map<number | string, Serializer> = new Map(); |
| 78 | + private typeInfoMap: Map<number | string, TypeInfo> = new Map(); |
| 79 | + |
| 80 | + private numberSerializer: null | Serializer = null; |
| 81 | + private int64Serializer: null | Serializer = null; |
| 82 | + private boolSerializer: null | Serializer = null; |
| 83 | + private dateSerializer: null | Serializer = null; |
| 84 | + private stringSerializer: null | Serializer = null; |
| 85 | + private setSerializer: null | Serializer = null; |
| 86 | + private arraySerializer: null | Serializer = null; |
| 87 | + private mapSerializer: null | Serializer = null; |
| 88 | + private uint8ArraySerializer: null | Serializer = null; |
| 89 | + private uint16ArraySerializer: null | Serializer = null; |
| 90 | + private uint32ArraySerializer: null | Serializer = null; |
| 91 | + private uint64ArraySerializer: null | Serializer = null; |
| 92 | + private int8ArraySerializer: null | Serializer = null; |
| 93 | + private int16ArraySerializer: null | Serializer = null; |
| 94 | + private int32ArraySerializer: null | Serializer = null; |
| 95 | + private int64ArraySerializer: null | Serializer = null; |
| 96 | + |
| 97 | + constructor(private fory: Fory) {} |
| 98 | + |
| 99 | + init() { |
| 100 | + this.initInternalSerializer(); |
| 101 | + } |
| 102 | + |
| 103 | + private initInternalSerializer() { |
| 104 | + const registerSerializer = (typeInfo: TypeInfo) => { |
| 105 | + return this.registerSerializer( |
| 106 | + typeInfo, |
| 107 | + new Gen(this.fory).generateSerializer(typeInfo), |
| 108 | + ); |
| 109 | + }; |
| 110 | + registerSerializer(Type.string()); |
| 111 | + registerSerializer(Type.any()); |
| 112 | + registerSerializer(Type.array(Type.any())); |
| 113 | + registerSerializer(Type.map(Type.any(), Type.any())); |
| 114 | + registerSerializer(Type.bool()); |
| 115 | + registerSerializer(Type.int8()); |
| 116 | + registerSerializer(Type.int16()); |
| 117 | + registerSerializer(Type.int32()); |
| 118 | + registerSerializer(Type.varInt32()); |
| 119 | + registerSerializer(Type.int64()); |
| 120 | + registerSerializer(Type.sliInt64()); |
| 121 | + registerSerializer(Type.float16()); |
| 122 | + registerSerializer(Type.float32()); |
| 123 | + registerSerializer(Type.float64()); |
| 124 | + registerSerializer(Type.timestamp()); |
| 125 | + registerSerializer(Type.duration()); |
| 126 | + registerSerializer(Type.set(Type.any())); |
| 127 | + registerSerializer(Type.binary()); |
| 128 | + registerSerializer(Type.boolArray()); |
| 129 | + registerSerializer(Type.int8Array()); |
| 130 | + registerSerializer(Type.int16Array()); |
| 131 | + registerSerializer(Type.int32Array()); |
| 132 | + registerSerializer(Type.int64Array()); |
| 133 | + registerSerializer(Type.float16Array()); |
| 134 | + registerSerializer(Type.float32Array()); |
| 135 | + registerSerializer(Type.float64Array()); |
| 136 | + |
| 137 | + this.numberSerializer = this.getSerializerById(TypeId.FLOAT64); |
| 138 | + this.int64Serializer = this.getSerializerById(TypeId.INT64); |
| 139 | + this.boolSerializer = this.getSerializerById(TypeId.BOOL); |
| 140 | + this.dateSerializer = this.getSerializerById(TypeId.TIMESTAMP); |
| 141 | + this.stringSerializer = this.getSerializerById(TypeId.STRING); |
| 142 | + this.setSerializer = this.getSerializerById(TypeId.SET); |
| 143 | + this.arraySerializer = this.getSerializerById(TypeId.LIST); |
| 144 | + this.mapSerializer = this.getSerializerById(TypeId.MAP); |
| 145 | + this.uint8ArraySerializer = this.getSerializerById(TypeId.UINT8_ARRAY); |
| 146 | + this.uint16ArraySerializer = this.getSerializerById(TypeId.UINT16_ARRAY); |
| 147 | + this.uint32ArraySerializer = this.getSerializerById(TypeId.UINT32_ARRAY); |
| 148 | + this.uint64ArraySerializer = this.getSerializerById(TypeId.UINT64_ARRAY); |
| 149 | + this.int8ArraySerializer = this.getSerializerById(TypeId.INT8_ARRAY); |
| 150 | + this.int16ArraySerializer = this.getSerializerById(TypeId.INT16_ARRAY); |
| 151 | + this.int32ArraySerializer = this.getSerializerById(TypeId.INT32_ARRAY); |
| 152 | + this.int64ArraySerializer = this.getSerializerById(TypeId.INT64_ARRAY); |
| 153 | + } |
| 154 | + |
| 155 | + getTypeInfo(typeIdOrName: number | string) { |
| 156 | + return this.typeInfoMap.get(typeIdOrName); |
| 157 | + } |
| 158 | + |
| 159 | + registerSerializer( |
| 160 | + typeInfo: TypeInfo, |
| 161 | + serializer: Serializer = uninitSerialize, |
| 162 | + ) { |
| 163 | + const typeId = |
| 164 | + typeof typeInfo.computeTypeId === "function" |
| 165 | + ? typeInfo.computeTypeId(this.fory) |
| 166 | + : typeInfo.typeId; |
| 167 | + |
| 168 | + if (!TypeId.isNamedType(typeId)) { |
| 169 | + const id = typeId; |
| 170 | + this.typeInfoMap.set(id, typeInfo); |
| 171 | + if (id <= 0xff) { |
| 172 | + if (this.internalSerializer[id]) { |
| 173 | + Object.assign(this.internalSerializer[id], serializer); |
| 174 | + } else { |
| 175 | + this.internalSerializer[id] = { ...serializer }; |
| 176 | + } |
| 177 | + return this.internalSerializer[id]; |
| 178 | + } else { |
| 179 | + if (this.customSerializer.has(id)) { |
| 180 | + Object.assign(this.customSerializer.get(id)!, serializer); |
| 181 | + } else { |
| 182 | + this.customSerializer.set(id, { ...serializer }); |
| 183 | + } |
| 184 | + return this.customSerializer.get(id); |
| 185 | + } |
| 186 | + } else { |
| 187 | + const namedTypeInfo = typeInfo.castToStruct(); |
| 188 | + const name = namedTypeInfo.named!; |
| 189 | + if (this.customSerializer.has(name)) { |
| 190 | + Object.assign(this.customSerializer.get(name)!, serializer); |
| 191 | + } else { |
| 192 | + this.customSerializer.set(name, { ...serializer }); |
| 193 | + } |
| 194 | + this.typeInfoMap.set(name, typeInfo); |
| 195 | + return this.customSerializer.get(name); |
| 196 | + } |
| 197 | + } |
| 198 | + |
| 199 | + typeInfoExists(typeInfo: TypeInfo) { |
| 200 | + if (typeInfo.isNamedType) { |
| 201 | + return this.typeInfoMap.has(typeInfo.castToStruct().named!); |
| 202 | + } |
| 203 | + return this.typeInfoMap.has(typeInfo.typeId); |
| 204 | + } |
| 205 | + |
| 206 | + getSerializerByTypeInfo(typeInfo: TypeInfo) { |
| 207 | + const typeId = |
| 208 | + typeof typeInfo.computeTypeId === "function" |
| 209 | + ? typeInfo.computeTypeId(this.fory) |
| 210 | + : (typeInfo as any)._typeId; |
| 211 | + |
| 212 | + if (TypeId.isNamedType(typeId)) { |
| 213 | + return this.customSerializer.get(typeInfo.castToStruct().named!); |
| 214 | + } |
| 215 | + return this.getSerializerById(typeId, typeInfo.userTypeId); |
| 216 | + } |
| 217 | + |
| 218 | + getSerializerById(id: number, _userTypeId?: number) { |
| 219 | + if (id <= 0xff) { |
| 220 | + return this.internalSerializer[id]!; |
| 221 | + } else { |
| 222 | + return this.customSerializer.get(id)!; |
| 223 | + } |
| 224 | + } |
| 225 | + |
| 226 | + getSerializerByName(typeIdOrName: number | string) { |
| 227 | + return this.customSerializer.get(typeIdOrName); |
| 228 | + } |
| 229 | + |
| 230 | + getSerializerByData(v: any) { |
| 231 | + if (typeof v === "number") return this.numberSerializer; |
| 232 | + if (typeof v === "string") return this.stringSerializer; |
| 233 | + if (v instanceof Uint8Array) return this.uint8ArraySerializer; |
| 234 | + if (v instanceof Uint16Array) return this.uint16ArraySerializer; |
| 235 | + if (v instanceof Uint32Array) return this.uint32ArraySerializer; |
| 236 | + if (v instanceof BigUint64Array) return this.uint64ArraySerializer; |
| 237 | + if (v instanceof Int8Array) return this.int8ArraySerializer; |
| 238 | + if (v instanceof Int16Array) return this.int16ArraySerializer; |
| 239 | + if (v instanceof Int32Array) return this.int32ArraySerializer; |
| 240 | + if (v instanceof BigInt64Array) return this.int64ArraySerializer; |
| 241 | + if (Array.isArray(v)) return this.arraySerializer; |
| 242 | + if (typeof v === "boolean") return this.boolSerializer; |
| 243 | + if (typeof v === "bigint") return this.int64Serializer; |
| 244 | + if (v instanceof Date) return this.dateSerializer; |
| 245 | + if (v instanceof Map) return this.mapSerializer; |
| 246 | + if (v instanceof Set) return this.setSerializer; |
| 247 | + |
| 248 | + if (typeof v === "object" && v !== null && ForyTypeInfoSymbol in v) { |
| 249 | + const typeInfo = (v[ForyTypeInfoSymbol] as WithForyClsInfo) |
| 250 | + .structTypeInfo; |
| 251 | + return this.getSerializerByTypeInfo(typeInfo); |
| 252 | + } |
| 253 | + |
| 254 | + throw new Error( |
| 255 | + `Failed to detect the Fory type from JavaScript type: ${typeof v}`, |
| 256 | + ); |
| 257 | + } |
| 258 | +} |
0 commit comments