You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+159-3Lines changed: 159 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -266,11 +266,167 @@ Client-side:
266
266
</script>
267
267
````
268
268
269
+
## Using with TypeScript
270
+
The entire project is written in TypeScript, and declaration files are automatically generated. That means that if you are using TypeScript, the compiler can automatically infer the type of the various values exported from `structure-bytes`. To import the package, use:
271
+
````javascript
272
+
import*assbfrom'structure-bytes'
273
+
````
274
+
One of the most useful parts of having typings is that the compiler can automatically infer what types of valus a `Type` can serialize. For example:
275
+
````javascript
276
+
let type =newsb.StructType({
277
+
abc:newsb.DoubleType,
278
+
def:newsb.MapType(
279
+
newsb.StringType,
280
+
newsb.DayType
281
+
)
282
+
})
283
+
type.valueBuffer(/*...*/)
284
+
/*
285
+
If you hover over "valueBuffer", you can see
286
+
that it requires the value to be of type:
287
+
{ abc: number | string, def: Map<string, Date> }
288
+
*/
289
+
````
290
+
You can even add explicit `VALUE` generics to make the compiler check that your `Type` serializes the correct types of values.
291
+
292
+
With `StructType`:
293
+
````typescript
294
+
classCar {
295
+
constructor(
296
+
publicmake:string,
297
+
publicmodel:string,
298
+
publicyear:number
299
+
) {}
300
+
}
301
+
let structType =newsb.StructType<Car>({
302
+
make: newsb.StringType,
303
+
model: newsb.StringType,
304
+
year: newsb.UnsignedShortType
305
+
})
306
+
//The compiler would have complained if one of the fields were missing
307
+
//or one of the field's types didn't match the type of the field's values,
308
+
//e.g. "make: new sb.BooleanType"
309
+
````
310
+
If you have transient fields (i.e. they shouldn't be serialized), you can create a separate interface for the fields that should be serialized:
With `ChoiceType` (and similarly for `NamedChoiceType`), you can let the type be inferred automatically if each of the possible types writes the same type of values:
331
+
````javascript
332
+
let type =newsb.ChoiceType([ //Type<number | string>
333
+
newsb.ByteType,
334
+
newsb.ShortType,
335
+
newsb.IntType
336
+
])
337
+
````
338
+
However, if the value types are not the same, TypeScript will complain about them not matching, and you should express the union type explicitly:
339
+
````typescript
340
+
interfaceRGB {
341
+
r:number
342
+
g:number
343
+
b:number
344
+
}
345
+
interfaceHSV {
346
+
h:number
347
+
s:number
348
+
v:number
349
+
}
350
+
typeCSSColor=string
351
+
352
+
let choiceType =newsb.ChoiceType<RGB|HSV|CSSColor>([
353
+
newsb.StructType<RGB>({
354
+
r: newsb.FloatType,
355
+
g: newsb.FloatType,
356
+
b: newsb.FloatType
357
+
}),
358
+
newsb.StructType<HSV>({
359
+
h: newsb.FloatType,
360
+
s: newsb.FloatType,
361
+
v: newsb.FloatType
362
+
}),
363
+
newsb.StringType
364
+
])
365
+
````
366
+
A `RecursiveType` has no way to infer its value type, so you should always provide the `VALUE` generic:
367
+
````typescript
368
+
interfaceCons<A> {
369
+
head:A
370
+
tail:List<A>
371
+
}
372
+
interfaceList<A> {
373
+
list:Cons<A> |null//null for empty list
374
+
}
375
+
376
+
let recursiveType =newsb.RecursiveType<List<string>>('linked-list')
377
+
sb.registerType({
378
+
type: newsb.StructType<List<string>>({
379
+
list: newsb.OptionalType(
380
+
newsb.StructType<Cons<string>>({
381
+
head: newsb.StringType,
382
+
tail: recursiveType
383
+
})
384
+
)
385
+
}),
386
+
name: 'linked-list'
387
+
})
388
+
recursiveType.valueBuffer({
389
+
list: {
390
+
head: '1',
391
+
tail: {
392
+
list: {
393
+
head: '2',
394
+
tail: {list: null}
395
+
}
396
+
}
397
+
}
398
+
})
399
+
````
400
+
When reading types from buffers and streams, they will be of type `Type<any>`.
401
+
You should specify their value types before using them to write values:
402
+
````typescript
403
+
let booleanType =newsb.BooleanType
404
+
let readType =sb.r.type(booleanType.toBuffer()) //Type<any>
405
+
//Will throw a runtime error
406
+
readType.valueBuffer('abc')
407
+
408
+
//vs.
409
+
410
+
let castReadType:sb.Type<boolean> =sb.r.type(booleanType.toBuffer())
411
+
//Will throw a compiler error
412
+
castReadType.valueBuffer('abc')
413
+
````
414
+
415
+
It may also sometimes be useful to be more specific about what types of values you want to be able to serialize.
416
+
For example, if you want to serialize integer values that will always be represented as numbers (and never in string form), you can force the compiler to error out if you try to serialize a string value with the following:
417
+
````typescript
418
+
let intType:sb.Type<number> =newsb.IntType
419
+
//Now this is valid:
420
+
intType.valueBuffer(100)
421
+
//But this is not, even though it would be if you omitted the type annotation on intType:
422
+
intType.valueBuffer('100')
423
+
````
424
+
269
425
## Binary formats
270
426
In the following definitions, `uint8_t` means an 8-bit unsigned integer. `flexInt` means a variable-length unsigned integer with the following format, where `X` represents either `0` or `1`:
271
-
-`[0b0XXXXXXX]` stores values from `0` to `2^7 - 1` in their unsigned 7-bit integer representations
272
-
-`[0b10XXXXXX, 0bXXXXXXXX]` stores values from `2^7` to `2^7 + 2^14 - 1`, where a value `x` is encoded into the unsigned 14-bit representation of `x - 2^7`
273
-
-`[0b110XXXXX, 0bXXXXXXXX, 0bXXXXXXXX]` stores values from `2^7 + 2^14` to `2^7 + 2^14 + 2^21 - 1`, where a value `x` is encoded into the unsigned 14-bit representation of `x - (2^7 + 2^14)`
427
+
-`[0b0XXXXXXX]` stores values from `0` to `2**7 - 1` in their unsigned 7-bit integer representations
428
+
-`[0b10XXXXXX, 0bXXXXXXXX]` stores values from `2**7` to `2**7 + 2**14 - 1`, where a value `x` is encoded into the unsigned 14-bit representation of `x - 2**7`
429
+
-`[0b110XXXXX, 0bXXXXXXXX, 0bXXXXXXXX]` stores values from `2**7 + 2**14` to `2**7 + 2**14 + 2**21 - 1`, where a value `x` is encoded into the unsigned 21-bit representation of `x - (2**7 + 2**14)`
<h2id="using-with-typescript">Using with TypeScript</h2>
331
+
<p>The entire project is written in TypeScript, and declaration files are automatically generated. That means that if you are using TypeScript, the compiler can automatically infer the type of the various values exported from <code>structure-bytes</code>. To import the package, use:</p>
<p>One of the most useful parts of having typings is that the compiler can automatically infer what types of valus a <code>Type</code> can serialize. For example:</p>
335
+
<pre><codeclass="lang-javascript"><spanclass="hljs-keyword">let</span> type = <spanclass="hljs-keyword">new</span> sb.StructType({
{ abc: number | string, def: Map<string, Date> }
347
+
*/</span>
348
+
</code></pre>
349
+
<p>You can even add explicit <code>VALUE</code> generics to make the compiler check that your <code>Type</code> serializes the correct types of values.</p>
350
+
<p>With <code>StructType</code>:</p>
351
+
<pre><codeclass="lang-typescript"><spanclass="hljs-keyword">class</span> Car {
<spanclass="hljs-comment">//The compiler would have complained if one of the fields were missing</span>
364
+
<spanclass="hljs-comment">//or one of the field's types didn't match the type of the field's values,</span>
365
+
<spanclass="hljs-comment">//e.g. "make: new sb.BooleanType"</span>
366
+
</code></pre>
367
+
<p>If you have transient fields (i.e. they shouldn't be serialized), you can create a separate interface for the fields that should be serialized:</p>
<p>With <code>ChoiceType</code> (and similarly for <code>NamedChoiceType</code>), you can let the type be inferred automatically if each of the possible types writes the same type of values:</p>
386
+
<pre><codeclass="lang-javascript"><spanclass="hljs-keyword">let</span> type = <spanclass="hljs-keyword">new</span> sb.ChoiceType([ <spanclass="hljs-comment">//Type<number | string></span>
<p>However, if the value types are not the same, TypeScript will complain about them not matching, and you should express the union type explicitly:</p>
<p>It may also sometimes be useful to be more specific about what types of values you want to be able to serialize.
466
+
For example, if you want to serialize integer values that will always be represented as numbers (and never in string form), you can force the compiler to error out if you try to serialize a string value with the following:</p>
<p>In the following definitions, <code>uint8_t</code> means an 8-bit unsigned integer. <code>flexInt</code> means a variable-length unsigned integer with the following format, where <code>X</code> represents either <code>0</code> or <code>1</code>:</p>
332
475
<ul>
333
-
<li><code>[0b0XXXXXXX]</code> stores values from <code>0</code> to <code>2^7 - 1</code> in their unsigned 7-bit integer representations</li>
334
-
<li><code>[0b10XXXXXX, 0bXXXXXXXX]</code> stores values from <code>2^7</code> to <code>2^7 + 2^14 - 1</code>, where a value <code>x</code> is encoded into the unsigned 14-bit representation of <code>x - 2^7</code></li>
335
-
<li><code>[0b110XXXXX, 0bXXXXXXXX, 0bXXXXXXXX]</code> stores values from <code>2^7 + 2^14</code> to <code>2^7 + 2^14 + 2^21 - 1</code>, where a value <code>x</code> is encoded into the unsigned 14-bit representation of <code>x - (2^7 + 2^14)</code></li>
476
+
<li><code>[0b0XXXXXXX]</code> stores values from <code>0</code> to <code>2**7 - 1</code> in their unsigned 7-bit integer representations</li>
477
+
<li><code>[0b10XXXXXX, 0bXXXXXXXX]</code> stores values from <code>2**7</code> to <code>2**7 + 2**14 - 1</code>, where a value <code>x</code> is encoded into the unsigned 14-bit representation of <code>x - 2**7</code></li>
478
+
<li><code>[0b110XXXXX, 0bXXXXXXXX, 0bXXXXXXXX]</code> stores values from <code>2**7 + 2**14</code> to <code>2**7 + 2**14 + 2**21 - 1</code>, where a value <code>x</code> is encoded into the unsigned 21-bit representation of <code>x - (2**7 + 2**14)</code></li>
336
479
<li>and so on, up to 8-byte representations</li>
337
480
</ul>
338
481
<p>All numbers are stored in big-endian format.</p>
0 commit comments