@@ -86,39 +86,161 @@ function deserializeValue(df: DataView, offset: number): [unknown, number] {
86
86
}
87
87
// BigInt
88
88
case "Z" . charCodeAt ( 0 ) : {
89
- // Read the bitfield which contains both sign and length information
90
- const [ bitfield , bytesReadForBitfield ] = decodeVarint ( df , offset + 1 ) ;
89
+ return deserializeBigInt ( df , offset + 1 ) ;
90
+ }
91
+ case "A" . charCodeAt ( 0 ) : {
92
+ return deserializeDenseJSArray ( df , offset + 1 ) ;
93
+ }
94
+ case "o" . charCodeAt ( 0 ) : {
95
+ // JavaScript Object
96
+ return deserializeJSObject ( df , offset + 1 ) ;
97
+ }
98
+
99
+ default :
100
+ throw new Error (
101
+ `Unsupported type: ${ String . fromCharCode ( type ) } (${ type } )`
102
+ ) ;
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Deserializes a JavaScript object
108
+ * @param df DataView containing the serialized data
109
+ * @param offset Current offset in the DataView (after the type byte)
110
+ */
111
+ function deserializeJSObject (
112
+ df : DataView ,
113
+ offset : number
114
+ ) : [ Record < string | number , unknown > , number ] {
115
+ const obj : Record < string | number , unknown > = { } ;
116
+ let currentOffset = offset ;
117
+ let propertyCount = 0 ;
118
+
119
+ // Keep reading key-value pairs until we find the end marker
120
+ while ( df . getUint8 ( currentOffset ) !== "{" . charCodeAt ( 0 ) ) {
121
+ // Read property key
122
+ const [ key , keyOffset ] = deserializeValue ( df , currentOffset ) ;
123
+ currentOffset = keyOffset ;
124
+
125
+ // Read property value
126
+ const [ value , valueOffset ] = deserializeValue ( df , currentOffset ) ;
127
+ currentOffset = valueOffset ;
128
+
129
+ // Set property on object
130
+ if ( typeof key === "string" || typeof key === "number" ) {
131
+ obj [ key ] = value ;
132
+ }
133
+
134
+ propertyCount ++ ;
135
+ }
136
+
137
+ // Skip the end marker
138
+ currentOffset ++ ;
139
+
140
+ // Read numProperties for validation
141
+ const [ numProperties , propBytesRead ] = decodeVarint ( df , currentOffset ) ;
142
+ currentOffset += propBytesRead ;
143
+
144
+ // Validate that we read the expected number of properties
145
+ if ( propertyCount !== numProperties ) {
146
+ throw new Error (
147
+ `Expected ${ numProperties } properties, but read ${ propertyCount } `
148
+ ) ;
149
+ }
150
+
151
+ return [ obj , currentOffset ] ;
152
+ }
153
+
154
+ /**
155
+ * Deserializes a dense JavaScript array
156
+ * @param df DataView containing the serialized data
157
+ * @param offset Current offset in the DataView (after the type byte)
158
+ */
159
+ function deserializeDenseJSArray (
160
+ df : DataView ,
161
+ offset : number
162
+ ) : [ unknown [ ] , number ] {
163
+ const [ length , bytesRead ] = decodeVarint ( df , offset ) ;
164
+ const array : unknown [ ] = [ ] ;
165
+ let currentOffset = offset + bytesRead ;
166
+
167
+ // Read each array element
168
+ for ( let i = 0 ; i < length ; i ++ ) {
169
+ const [ value , nextOffset ] = deserializeValue ( df , currentOffset ) ;
170
+ array . push ( value ) ;
171
+ currentOffset = nextOffset ;
172
+ }
91
173
92
- // Extract sign from the bitfield (lowest bit is the sign: 0 = positive, 1 = negative)
93
- const isNegative = ( bitfield & 1 ) === 1 ;
174
+ // Check for the end marker
175
+ if ( df . getUint8 ( currentOffset ) !== "$" . charCodeAt ( 0 ) ) {
176
+ throw new Error ( "Expected end of array marker" ) ;
177
+ }
94
178
95
- // Calculate the byte length (based on V8's implementation)
96
- // The length is stored in the upper bits of the bitfield
97
- const byteLength = Math . floor ( bitfield / 2 ) ; // Simplified approximation
179
+ // Skip the end marker
180
+ currentOffset ++ ;
98
181
99
- // Read the bytes for the BigInt digits
100
- const digitsStart = offset + 1 + bytesReadForBitfield ;
101
- let bigintValue = 0n ;
182
+ // Read numProperties and length
183
+ const [ numProperties , propBytesRead ] = decodeVarint ( df , currentOffset ) ;
184
+ currentOffset += propBytesRead ;
102
185
103
- // Read each byte and build the BigInt
104
- for ( let i = 0 ; i < byteLength ; i ++ ) {
105
- // BigInts are stored in little-endian format in V8
106
- const byte = df . getUint8 ( digitsStart + i ) ;
107
- bigintValue = bigintValue + ( BigInt ( byte ) << BigInt ( 8 * i ) ) ;
108
- }
186
+ const [ arrayLength , lengthBytesRead ] = decodeVarint ( df , currentOffset ) ;
187
+ currentOffset += lengthBytesRead ;
109
188
110
- // Apply sign
111
- if ( isNegative ) {
112
- bigintValue = - bigintValue ;
113
- }
189
+ // Read properties if any (key-value pairs)
190
+ for ( let i = 0 ; i < numProperties ; i ++ ) {
191
+ // Read property key
192
+ const [ key , keyOffset ] = deserializeValue ( df , currentOffset ) ;
193
+ currentOffset = keyOffset ;
114
194
115
- return [ bigintValue , digitsStart + byteLength ] ;
195
+ // Read property value
196
+ const [ value , valueOffset ] = deserializeValue ( df , currentOffset ) ;
197
+ currentOffset = valueOffset ;
198
+
199
+ // Set property on array
200
+ if ( typeof key === "string" || typeof key === "number" ) {
201
+ ( array as any ) [ key ] = value ;
116
202
}
117
- default :
118
- throw new Error (
119
- `Unsupported type: ${ String . fromCharCode ( type ) } (${ type } )`
120
- ) ;
121
203
}
204
+
205
+ // Set the array length to match the serialized length
206
+ array . length = arrayLength ;
207
+
208
+ return [ array , currentOffset ] ;
209
+ }
210
+
211
+ /**
212
+ * Deserializes a BigInt value
213
+ * @param df DataView containing the serialized data
214
+ * @param offset Current offset in the DataView (after the type byte)
215
+ */
216
+ function deserializeBigInt ( df : DataView , offset : number ) : [ bigint , number ] {
217
+ // Read the bitfield which contains both sign and length information
218
+ const [ bitfield , bytesReadForBitfield ] = decodeVarint ( df , offset ) ;
219
+
220
+ // Extract sign from the bitfield (lowest bit is the sign: 0 = positive, 1 = negative)
221
+ const isNegative = ( bitfield & 1 ) === 1 ;
222
+
223
+ // Calculate the byte length (based on V8's implementation)
224
+ // The length is stored in the upper bits of the bitfield
225
+ const byteLength = Math . floor ( bitfield / 2 ) ; // Simplified approximation
226
+
227
+ // Read the bytes for the BigInt digits
228
+ const digitsStart = offset + bytesReadForBitfield ;
229
+ let bigintValue = 0n ;
230
+
231
+ // Read each byte and build the BigInt
232
+ for ( let i = 0 ; i < byteLength ; i ++ ) {
233
+ // BigInts are stored in little-endian format in V8
234
+ const byte = df . getUint8 ( digitsStart + i ) ;
235
+ bigintValue = bigintValue + ( BigInt ( byte ) << BigInt ( 8 * i ) ) ;
236
+ }
237
+
238
+ // Apply sign
239
+ if ( isNegative ) {
240
+ bigintValue = - bigintValue ;
241
+ }
242
+
243
+ return [ bigintValue , digitsStart + byteLength ] ;
122
244
}
123
245
124
246
/**
0 commit comments