@2702rebels/wpidata 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,41 +4,28 @@ import { DataChannel, DataTransformer, DataTypeImpl, StructuredTypeDescriptor }
4
4
  type StructFieldType = "ref" | "bool" | "char" | "int8" | "int16" | "int32" | "int64" | "uint8" | "uint16" | "uint32" | "uint64" | "float" | "double";
5
5
  /** Describes individual field in {@link StructDescriptor}. */
6
6
  type StructFieldDescriptor = {
7
- /** Field identifier */
8
- identifier: string;
9
- /** Field value type */
10
- type: StructFieldType;
11
- /** Reference for complex (nested) type */
12
- typeRef?: StructDescriptor | string;
13
- /** Offset to the packed field data in bytes */
14
- offset: number;
15
- /** Size of the packed field data in bytes */
16
- size: number;
17
- /** Fixed array size */
18
- arraySize?: number;
19
- /** Bit width of the field data (bit-field only) */
20
- bitWidth?: number;
21
- /** Bit shift for the field data (bit-field only) */
22
- bitShift?: number;
23
- /** Enum specification */
7
+ /** Field identifier */identifier: string; /** Field value type */
8
+ type: StructFieldType; /** Reference for complex (nested) type */
9
+ typeRef?: StructDescriptor | string; /** Offset to the packed field data in bytes */
10
+ offset: number; /** Size of the packed field data in bytes */
11
+ size: number; /** Fixed array size */
12
+ arraySize?: number; /** Bit width of the field data (bit-field only) */
13
+ bitWidth?: number; /** Bit shift for the field data (bit-field only) */
14
+ bitShift?: number; /** Enum specification */
24
15
  enum?: Map<number, string>;
25
16
  };
26
17
  /** Describes named struct type. */
27
18
  type StructDescriptor = {
28
- /** Struct type name */
29
- name: string;
30
- /** Struct fields in packed order */
31
- fields: ReadonlyArray<StructFieldDescriptor>;
32
- /** Total packed size in bytes */
33
- size: number;
34
- /** Missing dependencies */
19
+ /** Struct type name */name: string; /** Struct fields in packed order */
20
+ fields: ReadonlyArray<StructFieldDescriptor>; /** Total packed size in bytes */
21
+ size: number; /** Missing dependencies */
35
22
  unresolved?: Set<string>;
36
23
  };
37
24
  type UnpackStructOptions = {
38
25
  /**
39
- * Indicates that integer numeric values with enum specification should be converted
40
- * to the corresponding enum string value if possible.
41
- */
26
+ * Indicates that integer numeric values with enum specification should be converted
27
+ * to the corresponding enum string value if possible.
28
+ */
42
29
  useEnum?: boolean;
43
30
  };
44
31
  /**
@@ -68,56 +55,56 @@ declare class StructRepository {
68
55
  /** Descriptors in the repository. */
69
56
  readonly descriptors: Map<string, StructDescriptor>;
70
57
  /**
71
- * Computes field bte offsets and returns total packed size in bytes.
72
- *
73
- * This method assumes that all fields have resolved external dependencies
74
- * and will compute byte offsets and bit shifts for bit-field packed fields.
75
- */
58
+ * Computes field bte offsets and returns total packed size in bytes.
59
+ *
60
+ * This method assumes that all fields have resolved external dependencies
61
+ * and will compute byte offsets and bit shifts for bit-field packed fields.
62
+ */
76
63
  private static computeFieldOffsets;
77
64
  /**
78
- * Attempts to finalize any unresolved descriptors with the recently resolved one.
79
- */
65
+ * Attempts to finalize any unresolved descriptors with the recently resolved one.
66
+ */
80
67
  private resolve;
81
68
  /**
82
- * Determines whether type can be transformed, indicating that
83
- * the parsed type descriptor is present.
84
- *
85
- * @param name struct type name
86
- */
69
+ * Determines whether type can be transformed, indicating that
70
+ * the parsed type descriptor is present.
71
+ *
72
+ * @param name struct type name
73
+ */
87
74
  canTransform(name: string): boolean;
88
75
  /**
89
- * Gets the struct type serialized size in bytes.
90
- *
91
- * @param name struct type name
92
- */
76
+ * Gets the struct type serialized size in bytes.
77
+ *
78
+ * @param name struct type name
79
+ */
93
80
  getSize(name: string): number;
94
81
  /**
95
- * Unpacks serialized struct data into JSON object.
96
- *
97
- * @param name struct type name
98
- * @param data serialized binary data
99
- * @param options additional options
100
- */
82
+ * Unpacks serialized struct data into JSON object.
83
+ *
84
+ * @param name struct type name
85
+ * @param data serialized binary data
86
+ * @param options additional options
87
+ */
101
88
  unpack(name: string, data: DataView<ArrayBufferLike> | Uint8Array<ArrayBufferLike>, options?: UnpackStructOptions): Record<string, unknown>;
102
89
  /**
103
- * Packs JSON object into serialized struct data.
104
- *
105
- * @param name struct type name
106
- * @param value JSON object to pack
107
- */
90
+ * Packs JSON object into serialized struct data.
91
+ *
92
+ * @param name struct type name
93
+ * @param value JSON object to pack
94
+ */
108
95
  pack(name: string, value: Record<string, unknown>): Uint8Array<ArrayBuffer>;
109
96
  /**
110
- * Parses struct schema and adds the resulting descriptor to the repository.
111
- *
112
- * The descriptor may not be fully processed if it references other structs that
113
- * we have not seen yet. Such pending descriptors will be processed automatically,
114
- * once corresponding structs have been added. This code checks for circular
115
- * dependencies and will fail when one is detected.
116
- *
117
- * @param name struct type name
118
- * @param data struct schema in UTF-8 encoded binary representation
119
- * @returns parsed descriptor or `null` if the operation failed
120
- */
97
+ * Parses struct schema and adds the resulting descriptor to the repository.
98
+ *
99
+ * The descriptor may not be fully processed if it references other structs that
100
+ * we have not seen yet. Such pending descriptors will be processed automatically,
101
+ * once corresponding structs have been added. This code checks for circular
102
+ * dependencies and will fail when one is detected.
103
+ *
104
+ * @param name struct type name
105
+ * @param data struct schema in UTF-8 encoded binary representation
106
+ * @returns parsed descriptor or `null` if the operation failed
107
+ */
121
108
  add(name: string, data: DataView<ArrayBufferLike> | Uint8Array<ArrayBufferLike>): StructDescriptor | null;
122
109
  }
123
110
  /** Implements {@link DataTransformer} interface for the `struct` serialization protocol. */
@@ -1 +1 @@
1
- {"version":3,"file":"struct.d.cts","names":[],"sources":["../../src/formats/struct.ts"],"sourcesContent":[],"mappings":";;;KAQY,eAAA;;AAAA,KAgBA,qBAAA,GAhBe;EAgBf;EAIJ,UAAA,EAAA,MAAA;EAEI;EAYH,IAAA,EAdD,eAcC;EAAG;EAIA,OAAA,CAAA,EAhBA,gBAgBgB,GAAA,MAAA;EAIJ;EAAd,MAAA,EAAA,MAAA;EAIK;EAAG,IAAA,EAAA,MAAA;EAUN;EAmBI,SAAM,CAAA,EAAA,MAAA;EAEL;EAAT,QAAA,CAAA,EAAA,MAAA;EAAuC;EAAX,QAAA,CAAA,EAAA,MAAA;EACtB;EACF,IAAA,CAAA,EA7CH,GA6CG,CAAA,MAAA,EAAA,MAAA,CAAA;CAAmB;;AAyBf,KAlEJ,gBAAA,GAkEQ;EAAsB;EAAqC,IAAA,EAAA,MAAA;EAAgB;EAAA,MAAA,EA9DrF,aA8DqF,CA9DvE,qBA8DuE,CAAA;EAAA;EAkclF,IAAA,EAAA,MAAA;EAIgB;EAAA,UAAA,CAAA,EAhgBd,GAggBc,CAAA,MAAA,CAAA;CAyHV;AAAT,KA/mBE,mBAAA,GA+mBF;EAAuC;;;;EAYd,OAAA,CAAA,EAAA,OAAA;CAAuB;;;;;;;;AAsL1D;;;;AA0CuE,iBAx0BvD,MAAA,CAw0BuD,IAAA,EAAA,MAAA,EAAA,IAAA,EAt0B/D,QAs0B+D,CAt0BtD,eAs0BsD,CAAA,GAt0BnC,UAs0BmC,CAt0BxB,eAs0BwB,CAAA,EAAA,UAAA,EAr0BzD,gBAq0ByD,EAAA,OAAA,CAAA,EAp0B3D,mBAo0B2D,CAAA,EAp0BxC,MAo0BwC,CAAA,MAAA,EAAA,OAAA,CAAA;;;;;;;;;iBA3yBvD,IAAA,sBAA0B,qCAAqC,mBAAgB,WAAA;;cAkclF,gBAAA;;;wBAIgB,YAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BAyHnB,SAAS,mBAAmB,WAAW,4BACnC,sBAAmB;;;;;;;4BAWE,0BAAuB,WAAA;;;;;;;;;;;;;0BAgBzB,SAAS,mBAAmB,WAAW,mBAAmB;;;cAsK9E,qBAAA,YAAiC;;0EAOtB,0BACnB;;qCAkCuC,2BAA2B;mCAkC7B,2BAA2B"}
1
+ {"version":3,"file":"struct.d.cts","names":[],"sources":["../../src/formats/struct.ts"],"mappings":";;;KAQY,eAAA;AAAA;AAAA,KAgBA,qBAAA;EAAA,uBAAA,UAAA;EAAA,IAAA,EAIJ,eAAA;EAAA,OAAA,GAEI,gBAAA;EAAA,MAAA;EAAA,IAAA;EAAA,SAAA;EAAA,QAAA;EAAA,QAAA;EAAA,IAAA,GAYH,GAAA;AAAA;AAAA;AAAA,KAIG,gBAAA;EAAA,uBAAA,IAAA;EAAA,MAAA,EAIF,aAAA,CAAc,qBAAA;EAAA,IAAA;EAAA,UAAA,GAIT,GAAA;AAAA;AAAA,KAUH,mBAAA;EAAA;AAmBZ;;;EAnBY,OAAA;AAAA;AAAA;AAmBZ;;;;;;;;;AA6BA;AAhDY,iBAmBI,MAAA,CAAA,IAAA,UAAA,IAAA,EAER,QAAA,CAAS,eAAA,IAAmB,UAAA,CAAW,eAAA,GAAA,UAAA,EACjC,gBAAA,EAAA,OAAA,GACF,mBAAA,GAAmB,MAAA;AAAA;;AAyB/B;;;;;;AAzB+B,iBAyBf,IAAA,CAAA,IAAA,UAAA,KAAA,EAA0B,MAAA,mBAAA,UAAA,EAAqC,gBAAA,GAAgB,UAAA,CAAA,WAAA;AAAA;AAAA,cAgelF,gBAAA;EAAA,iBAAA,UAAA;EAAA;EAAA,SAAA,WAAA,EAIgB,GAAA,SAAA,gBAAA;EAAA;;;;;;EAAA,eAAA,mBAAA;EAAA;;;EAAA,QAAA,OAAA;EAAA;;;;;;EAAA,aAAA,IAAA;EAAA;;;;;EAAA,QAAA,IAAA;EAAA;;;;;;;EAAA,OAAA,IAAA,UAAA,IAAA,EAyHnB,QAAA,CAAS,eAAA,IAAmB,UAAA,CAAW,eAAA,GAAA,OAAA,GACnC,mBAAA,GAAmB,MAAA;EAAA;;;;;;EAAA,KAAA,IAAA,UAAA,KAAA,EAWE,MAAA,oBAAuB,UAAA,CAAA,WAAA;EAAA;;;;;;;;AAsL1D;;;;EAtL0D,IAAA,IAAA,UAAA,IAAA,EAgBzB,QAAA,CAAS,eAAA,IAAmB,UAAA,CAAW,eAAA,IAAmB,gBAAA;AAAA;AAAA;AAAA,cAsK9E,qBAAA,YAAiC,eAAA;EAAA,iBAAA,IAAA;EAAA,QAAA,MAAA,UAAA,IAAA,UAAA,IAAA,UAAA,QAAA,YAOtB,MAAA,oBACnB,WAAA;EAAA,OAAA,QAAA,UAAA,KAAA;EAAA,YAAA,KAAA,WAAA,IAAA,GAkCuC,wBAAA,GAA2B,YAAA;EAAA,UAAA,KAAA,WAAA,IAAA,GAkC7B,wBAAA,GAA2B,UAAA;EAAA,aAAA,IAAA;AAAA"}
@@ -4,41 +4,28 @@ import { DataChannel, DataTransformer, DataTypeImpl, StructuredTypeDescriptor }
4
4
  type StructFieldType = "ref" | "bool" | "char" | "int8" | "int16" | "int32" | "int64" | "uint8" | "uint16" | "uint32" | "uint64" | "float" | "double";
5
5
  /** Describes individual field in {@link StructDescriptor}. */
6
6
  type StructFieldDescriptor = {
7
- /** Field identifier */
8
- identifier: string;
9
- /** Field value type */
10
- type: StructFieldType;
11
- /** Reference for complex (nested) type */
12
- typeRef?: StructDescriptor | string;
13
- /** Offset to the packed field data in bytes */
14
- offset: number;
15
- /** Size of the packed field data in bytes */
16
- size: number;
17
- /** Fixed array size */
18
- arraySize?: number;
19
- /** Bit width of the field data (bit-field only) */
20
- bitWidth?: number;
21
- /** Bit shift for the field data (bit-field only) */
22
- bitShift?: number;
23
- /** Enum specification */
7
+ /** Field identifier */identifier: string; /** Field value type */
8
+ type: StructFieldType; /** Reference for complex (nested) type */
9
+ typeRef?: StructDescriptor | string; /** Offset to the packed field data in bytes */
10
+ offset: number; /** Size of the packed field data in bytes */
11
+ size: number; /** Fixed array size */
12
+ arraySize?: number; /** Bit width of the field data (bit-field only) */
13
+ bitWidth?: number; /** Bit shift for the field data (bit-field only) */
14
+ bitShift?: number; /** Enum specification */
24
15
  enum?: Map<number, string>;
25
16
  };
26
17
  /** Describes named struct type. */
27
18
  type StructDescriptor = {
28
- /** Struct type name */
29
- name: string;
30
- /** Struct fields in packed order */
31
- fields: ReadonlyArray<StructFieldDescriptor>;
32
- /** Total packed size in bytes */
33
- size: number;
34
- /** Missing dependencies */
19
+ /** Struct type name */name: string; /** Struct fields in packed order */
20
+ fields: ReadonlyArray<StructFieldDescriptor>; /** Total packed size in bytes */
21
+ size: number; /** Missing dependencies */
35
22
  unresolved?: Set<string>;
36
23
  };
37
24
  type UnpackStructOptions = {
38
25
  /**
39
- * Indicates that integer numeric values with enum specification should be converted
40
- * to the corresponding enum string value if possible.
41
- */
26
+ * Indicates that integer numeric values with enum specification should be converted
27
+ * to the corresponding enum string value if possible.
28
+ */
42
29
  useEnum?: boolean;
43
30
  };
44
31
  /**
@@ -68,56 +55,56 @@ declare class StructRepository {
68
55
  /** Descriptors in the repository. */
69
56
  readonly descriptors: Map<string, StructDescriptor>;
70
57
  /**
71
- * Computes field bte offsets and returns total packed size in bytes.
72
- *
73
- * This method assumes that all fields have resolved external dependencies
74
- * and will compute byte offsets and bit shifts for bit-field packed fields.
75
- */
58
+ * Computes field bte offsets and returns total packed size in bytes.
59
+ *
60
+ * This method assumes that all fields have resolved external dependencies
61
+ * and will compute byte offsets and bit shifts for bit-field packed fields.
62
+ */
76
63
  private static computeFieldOffsets;
77
64
  /**
78
- * Attempts to finalize any unresolved descriptors with the recently resolved one.
79
- */
65
+ * Attempts to finalize any unresolved descriptors with the recently resolved one.
66
+ */
80
67
  private resolve;
81
68
  /**
82
- * Determines whether type can be transformed, indicating that
83
- * the parsed type descriptor is present.
84
- *
85
- * @param name struct type name
86
- */
69
+ * Determines whether type can be transformed, indicating that
70
+ * the parsed type descriptor is present.
71
+ *
72
+ * @param name struct type name
73
+ */
87
74
  canTransform(name: string): boolean;
88
75
  /**
89
- * Gets the struct type serialized size in bytes.
90
- *
91
- * @param name struct type name
92
- */
76
+ * Gets the struct type serialized size in bytes.
77
+ *
78
+ * @param name struct type name
79
+ */
93
80
  getSize(name: string): number;
94
81
  /**
95
- * Unpacks serialized struct data into JSON object.
96
- *
97
- * @param name struct type name
98
- * @param data serialized binary data
99
- * @param options additional options
100
- */
82
+ * Unpacks serialized struct data into JSON object.
83
+ *
84
+ * @param name struct type name
85
+ * @param data serialized binary data
86
+ * @param options additional options
87
+ */
101
88
  unpack(name: string, data: DataView<ArrayBufferLike> | Uint8Array<ArrayBufferLike>, options?: UnpackStructOptions): Record<string, unknown>;
102
89
  /**
103
- * Packs JSON object into serialized struct data.
104
- *
105
- * @param name struct type name
106
- * @param value JSON object to pack
107
- */
90
+ * Packs JSON object into serialized struct data.
91
+ *
92
+ * @param name struct type name
93
+ * @param value JSON object to pack
94
+ */
108
95
  pack(name: string, value: Record<string, unknown>): Uint8Array<ArrayBuffer>;
109
96
  /**
110
- * Parses struct schema and adds the resulting descriptor to the repository.
111
- *
112
- * The descriptor may not be fully processed if it references other structs that
113
- * we have not seen yet. Such pending descriptors will be processed automatically,
114
- * once corresponding structs have been added. This code checks for circular
115
- * dependencies and will fail when one is detected.
116
- *
117
- * @param name struct type name
118
- * @param data struct schema in UTF-8 encoded binary representation
119
- * @returns parsed descriptor or `null` if the operation failed
120
- */
97
+ * Parses struct schema and adds the resulting descriptor to the repository.
98
+ *
99
+ * The descriptor may not be fully processed if it references other structs that
100
+ * we have not seen yet. Such pending descriptors will be processed automatically,
101
+ * once corresponding structs have been added. This code checks for circular
102
+ * dependencies and will fail when one is detected.
103
+ *
104
+ * @param name struct type name
105
+ * @param data struct schema in UTF-8 encoded binary representation
106
+ * @returns parsed descriptor or `null` if the operation failed
107
+ */
121
108
  add(name: string, data: DataView<ArrayBufferLike> | Uint8Array<ArrayBufferLike>): StructDescriptor | null;
122
109
  }
123
110
  /** Implements {@link DataTransformer} interface for the `struct` serialization protocol. */
@@ -1 +1 @@
1
- {"version":3,"file":"struct.d.mts","names":[],"sources":["../../src/formats/struct.ts"],"sourcesContent":[],"mappings":";;;KAQY,eAAA;;AAAA,KAgBA,qBAAA,GAhBe;EAgBf;EAIJ,UAAA,EAAA,MAAA;EAEI;EAYH,IAAA,EAdD,eAcC;EAAG;EAIA,OAAA,CAAA,EAhBA,gBAgBgB,GAAA,MAAA;EAIJ;EAAd,MAAA,EAAA,MAAA;EAIK;EAAG,IAAA,EAAA,MAAA;EAUN;EAmBI,SAAM,CAAA,EAAA,MAAA;EAEL;EAAT,QAAA,CAAA,EAAA,MAAA;EAAuC;EAAX,QAAA,CAAA,EAAA,MAAA;EACtB;EACF,IAAA,CAAA,EA7CH,GA6CG,CAAA,MAAA,EAAA,MAAA,CAAA;CAAmB;;AAyBf,KAlEJ,gBAAA,GAkEQ;EAAsB;EAAqC,IAAA,EAAA,MAAA;EAAgB;EAAA,MAAA,EA9DrF,aA8DqF,CA9DvE,qBA8DuE,CAAA;EAAA;EAkclF,IAAA,EAAA,MAAA;EAIgB;EAAA,UAAA,CAAA,EAhgBd,GAggBc,CAAA,MAAA,CAAA;CAyHV;AAAT,KA/mBE,mBAAA,GA+mBF;EAAuC;;;;EAYd,OAAA,CAAA,EAAA,OAAA;CAAuB;;;;;;;;AAsL1D;;;;AA0CuE,iBAx0BvD,MAAA,CAw0BuD,IAAA,EAAA,MAAA,EAAA,IAAA,EAt0B/D,QAs0B+D,CAt0BtD,eAs0BsD,CAAA,GAt0BnC,UAs0BmC,CAt0BxB,eAs0BwB,CAAA,EAAA,UAAA,EAr0BzD,gBAq0ByD,EAAA,OAAA,CAAA,EAp0B3D,mBAo0B2D,CAAA,EAp0BxC,MAo0BwC,CAAA,MAAA,EAAA,OAAA,CAAA;;;;;;;;;iBA3yBvD,IAAA,sBAA0B,qCAAqC,mBAAgB,WAAA;;cAkclF,gBAAA;;;wBAIgB,YAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BAyHnB,SAAS,mBAAmB,WAAW,4BACnC,sBAAmB;;;;;;;4BAWE,0BAAuB,WAAA;;;;;;;;;;;;;0BAgBzB,SAAS,mBAAmB,WAAW,mBAAmB;;;cAsK9E,qBAAA,YAAiC;;0EAOtB,0BACnB;;qCAkCuC,2BAA2B;mCAkC7B,2BAA2B"}
1
+ {"version":3,"file":"struct.d.mts","names":[],"sources":["../../src/formats/struct.ts"],"mappings":";;;KAQY,eAAA;AAAA;AAAA,KAgBA,qBAAA;EAAA,uBAAA,UAAA;EAAA,IAAA,EAIJ,eAAA;EAAA,OAAA,GAEI,gBAAA;EAAA,MAAA;EAAA,IAAA;EAAA,SAAA;EAAA,QAAA;EAAA,QAAA;EAAA,IAAA,GAYH,GAAA;AAAA;AAAA;AAAA,KAIG,gBAAA;EAAA,uBAAA,IAAA;EAAA,MAAA,EAIF,aAAA,CAAc,qBAAA;EAAA,IAAA;EAAA,UAAA,GAIT,GAAA;AAAA;AAAA,KAUH,mBAAA;EAAA;AAmBZ;;;EAnBY,OAAA;AAAA;AAAA;AAmBZ;;;;;;;;;AA6BA;AAhDY,iBAmBI,MAAA,CAAA,IAAA,UAAA,IAAA,EAER,QAAA,CAAS,eAAA,IAAmB,UAAA,CAAW,eAAA,GAAA,UAAA,EACjC,gBAAA,EAAA,OAAA,GACF,mBAAA,GAAmB,MAAA;AAAA;;AAyB/B;;;;;;AAzB+B,iBAyBf,IAAA,CAAA,IAAA,UAAA,KAAA,EAA0B,MAAA,mBAAA,UAAA,EAAqC,gBAAA,GAAgB,UAAA,CAAA,WAAA;AAAA;AAAA,cAgelF,gBAAA;EAAA,iBAAA,UAAA;EAAA;EAAA,SAAA,WAAA,EAIgB,GAAA,SAAA,gBAAA;EAAA;;;;;;EAAA,eAAA,mBAAA;EAAA;;;EAAA,QAAA,OAAA;EAAA;;;;;;EAAA,aAAA,IAAA;EAAA;;;;;EAAA,QAAA,IAAA;EAAA;;;;;;;EAAA,OAAA,IAAA,UAAA,IAAA,EAyHnB,QAAA,CAAS,eAAA,IAAmB,UAAA,CAAW,eAAA,GAAA,OAAA,GACnC,mBAAA,GAAmB,MAAA;EAAA;;;;;;EAAA,KAAA,IAAA,UAAA,KAAA,EAWE,MAAA,oBAAuB,UAAA,CAAA,WAAA;EAAA;;;;;;;;AAsL1D;;;;EAtL0D,IAAA,IAAA,UAAA,IAAA,EAgBzB,QAAA,CAAS,eAAA,IAAmB,UAAA,CAAW,eAAA,IAAmB,gBAAA;AAAA;AAAA;AAAA,cAsK9E,qBAAA,YAAiC,eAAA;EAAA,iBAAA,IAAA;EAAA,QAAA,MAAA,UAAA,IAAA,UAAA,IAAA,UAAA,QAAA,YAOtB,MAAA,oBACnB,WAAA;EAAA,OAAA,QAAA,UAAA,KAAA;EAAA,YAAA,KAAA,WAAA,IAAA,GAkCuC,wBAAA,GAA2B,YAAA;EAAA,UAAA,KAAA,WAAA,IAAA,GAkC7B,wBAAA,GAA2B,UAAA;EAAA,aAAA,IAAA;AAAA"}
@@ -72,9 +72,19 @@ function transformEnums(field, value) {
72
72
  function unpackStruct(sink, descriptor, view, byteOffset, transformer) {
73
73
  for (const field of descriptor.fields) if (field.type === "ref") {
74
74
  if (field.typeRef == null || typeof field.typeRef !== "object") throw error(`Failed to unpack struct data: field '${field.identifier}' references unresolved type`);
75
- const result = {};
76
- unpackStruct(result, field.typeRef, view, byteOffset + field.offset, transformer);
77
- sink[field.identifier] = result;
75
+ if (field.arraySize != null) {
76
+ const result = [];
77
+ for (let i = 0; i < field.arraySize; ++i) {
78
+ const v = {};
79
+ unpackStruct(v, field.typeRef, view, byteOffset + field.offset + i * field.size, transformer);
80
+ result.push(v);
81
+ }
82
+ sink[field.identifier] = result;
83
+ } else {
84
+ const result = {};
85
+ unpackStruct(result, field.typeRef, view, byteOffset + field.offset, transformer);
86
+ sink[field.identifier] = result;
87
+ }
78
88
  } else if (field.arraySize != null) if (field.type === "char") sink[field.identifier] = transformer(field, decodeStringValue(view, byteOffset + field.offset, field.arraySize));
79
89
  else {
80
90
  const result = [];
@@ -97,7 +107,10 @@ function packStruct(source, descriptor, view, byteOffset, transformer) {
97
107
  const value = source[field.identifier];
98
108
  if (field.type === "ref") {
99
109
  if (field.typeRef == null || typeof field.typeRef !== "object") throw error(`Failed to pack struct data: field '${field.identifier}' references unresolved type`);
100
- packStruct(value ?? {}, field.typeRef, view, byteOffset + field.offset, transformer);
110
+ if (field.arraySize != null) {
111
+ if (!Array.isArray(value) || value.length != field.arraySize) throw error(`Failed to pack struct data: field '${field.identifier}' must be an array of length ${field.arraySize}`);
112
+ for (let i = 0; i < field.arraySize; ++i) packStruct(value[i], field.typeRef, view, byteOffset + field.offset + i * field.size, transformer);
113
+ } else packStruct(value ?? {}, field.typeRef, view, byteOffset + field.offset, transformer);
101
114
  } else if (field.arraySize != null) if (field.type === "char") encodeStringValue(view, byteOffset + field.offset, field.arraySize, transformer(field, value) ?? "");
102
115
  else for (let i = 0; i < field.arraySize; ++i) encodePrimitiveValue(field, view, byteOffset + field.offset + i * field.size, transformer(field, value));
103
116
  else if (field.bitWidth != null) encodeBitFieldValue(field, view, byteOffset + field.offset, transformer(field, value));
@@ -1 +1 @@
1
- {"version":3,"file":"struct.mjs","names":["shift","n"],"sources":["../../src/formats/struct.ts"],"sourcesContent":["import { toDataView, toUint8Array } from \"../utils\";\n\nimport type { DataChannel, DataTransformer, DataTypeImpl, StructuredTypeDescriptor } from \"../abstractions\";\n\nconst error = (message: string) => {\n return new Error(message);\n};\n\nexport type StructFieldType =\n | \"ref\"\n | \"bool\"\n | \"char\"\n | \"int8\"\n | \"int16\"\n | \"int32\"\n | \"int64\"\n | \"uint8\"\n | \"uint16\"\n | \"uint32\"\n | \"uint64\"\n | \"float\"\n | \"double\";\n\n/** Describes individual field in {@link StructDescriptor}. */\nexport type StructFieldDescriptor = {\n /** Field identifier */\n identifier: string;\n /** Field value type */\n type: StructFieldType;\n /** Reference for complex (nested) type */\n typeRef?: StructDescriptor | string;\n /** Offset to the packed field data in bytes */\n offset: number;\n /** Size of the packed field data in bytes */\n size: number;\n /** Fixed array size */\n arraySize?: number;\n /** Bit width of the field data (bit-field only) */\n bitWidth?: number;\n /** Bit shift for the field data (bit-field only) */\n bitShift?: number;\n /** Enum specification */\n enum?: Map<number, string>;\n};\n\n/** Describes named struct type. */\nexport type StructDescriptor = {\n /** Struct type name */\n name: string;\n /** Struct fields in packed order */\n fields: ReadonlyArray<StructFieldDescriptor>;\n /** Total packed size in bytes */\n size: number;\n /** Missing dependencies */\n unresolved?: Set<string>;\n};\n\nconst utf8decoder = new TextDecoder(\"utf-8\", {\n // throw TypeError on invalid data instead of silent substitution\n fatal: true,\n});\n\nconst utf8encoder = new TextEncoder();\n\nexport type UnpackStructOptions = {\n /**\n * Indicates that integer numeric values with enum specification should be converted\n * to the corresponding enum string value if possible.\n */\n useEnum?: boolean;\n};\n\n/**\n * Unpacks serialized struct data into JSON object.\n *\n * Implementation of WPILiB packed struct serialization protocol\n * https://github.com/wpilibsuite/allwpilib/blob/main/wpiutil/doc/struct.adoc\n *\n * @param name struct type name\n * @param data serialized binary data\n * @param repository repository of available descriptors\n * @param options additional options\n */\nexport function unpack(\n name: string,\n data: DataView<ArrayBufferLike> | Uint8Array<ArrayBufferLike>,\n repository: StructRepository,\n options?: UnpackStructOptions\n) {\n const descriptor = repository.descriptors.get(name);\n if (descriptor == null) {\n throw error(`Failed to unpack struct data: missing '${name}' type definition`);\n }\n\n // descriptor exists but is not mapped yet due to unresolved dependencies\n if (descriptor.size === 0) {\n throw error(`Failed to unpack struct data: '${name}' type definition has unresolved dependencies`);\n }\n\n const result: Record<string, unknown> = {};\n unpackStruct(result, descriptor, toDataView(data), 0, options?.useEnum ? transformEnums : (_, v) => v);\n return result;\n}\n\n/**\n * Packs JSON object into serialized struct data.\n *\n * @param name struct type name\n * @param value JSON object to pack\n * @param repository repository of available descriptors\n * @returns ArrayBuffer containing serialized data\n */\nexport function pack(name: string, value: Record<string, unknown>, repository: StructRepository) {\n const descriptor = repository.descriptors.get(name);\n if (descriptor == null) {\n throw error(`Failed to pack struct data: missing '${name}' type definition`);\n }\n\n // descriptor exists but is not mapped yet due to unresolved dependencies\n if (descriptor.size === 0) {\n throw error(`Failed to pack struct data: '${name}' type definition has unresolved dependencies`);\n }\n\n const buffer = new ArrayBuffer(descriptor.size);\n const view = new DataView(buffer);\n\n packStruct(value, descriptor, view, 0, transformValue);\n return new Uint8Array(buffer);\n}\n\n/**\n * Transforms field values according to the field descriptor.\n *\n * Handles conversion of enum strings into their numeric representation.\n */\nfunction transformValue(field: StructFieldDescriptor, value: unknown) {\n if (field.enum != null && typeof value === \"string\") {\n for (const [key, v] of field.enum) {\n if (v === value) {\n return key;\n }\n }\n }\n\n return value;\n}\n\n/** Transforms numeric values to enum names for fields that support enums. */\nfunction transformEnums(field: StructFieldDescriptor, value: unknown) {\n if (field.enum != null && typeof value === \"number\") {\n const enumName = field.enum.get(value);\n if (enumName != null) {\n return enumName;\n }\n }\n\n return value;\n}\n\n/**\n * Unpacks data per descriptor specification and populates `sink` placeholder instance.\n *\n * @param sink target object to populate with parsed data\n * @param descriptor struct type descriptor\n * @param view source buffer view\n * @param byteOffset offset in bytes within `view`\n * @param transformer primitive field value transformer\n */\nfunction unpackStruct(\n sink: Record<string, unknown>,\n descriptor: StructDescriptor,\n view: DataView,\n byteOffset: number,\n transformer: (field: StructFieldDescriptor, value: unknown) => unknown\n) {\n for (const field of descriptor.fields) {\n if (field.type === \"ref\") {\n // nested structure\n if (field.typeRef == null || typeof field.typeRef !== \"object\") {\n throw error(`Failed to unpack struct data: field '${field.identifier}' references unresolved type`);\n }\n\n const result: Record<string, unknown> = {};\n unpackStruct(result, field.typeRef, view, byteOffset + field.offset, transformer);\n sink[field.identifier] = result;\n } else if (field.arraySize != null) {\n if (field.type === \"char\") {\n // array of chars is UTF-8 encoded string\n sink[field.identifier] = transformer(\n field,\n decodeStringValue(view, byteOffset + field.offset, field.arraySize)\n );\n } else {\n // array of booleans or numeric values\n const result: Array<unknown> = [];\n for (let i = 0; i < field.arraySize; ++i) {\n result.push(\n transformer(field, decodePrimitiveValue(field, view, byteOffset + field.offset + i * field.size))\n );\n }\n }\n } else if (field.bitWidth != null) {\n sink[field.identifier] = transformer(field, decodeBitFieldValue(field, view, byteOffset + field.offset));\n } else {\n sink[field.identifier] = transformer(field, decodePrimitiveValue(field, view, byteOffset + field.offset));\n }\n }\n}\n\n/**\n * Packs data per descriptor specification.\n *\n * @param source source object to pack\n * @param descriptor struct type descriptor\n * @param view target buffer view\n * @param byteOffset offset in bytes within `view`\n * @param transformer primitive field value transformer\n */\nfunction packStruct(\n source: Record<string, unknown>,\n descriptor: StructDescriptor,\n view: DataView,\n byteOffset: number,\n transformer: (field: StructFieldDescriptor, value: unknown) => unknown\n) {\n for (const field of descriptor.fields) {\n const value = source[field.identifier];\n\n if (field.type === \"ref\") {\n // nested structure\n if (field.typeRef == null || typeof field.typeRef !== \"object\") {\n throw error(`Failed to pack struct data: field '${field.identifier}' references unresolved type`);\n }\n\n packStruct((value ?? {}) as Record<string, unknown>, field.typeRef, view, byteOffset + field.offset, transformer);\n } else if (field.arraySize != null) {\n if (field.type === \"char\") {\n // array of chars is UTF-8 encoded string\n encodeStringValue(\n view,\n byteOffset + field.offset,\n field.arraySize,\n (transformer(field, value) ?? \"\") as string\n );\n } else {\n // array of booleans or numeric values\n for (let i = 0; i < field.arraySize; ++i) {\n encodePrimitiveValue(field, view, byteOffset + field.offset + i * field.size, transformer(field, value));\n }\n }\n } else if (field.bitWidth != null) {\n encodeBitFieldValue(field, view, byteOffset + field.offset, transformer(field, value));\n } else {\n encodePrimitiveValue(field, view, byteOffset + field.offset, transformer(field, value));\n }\n }\n}\n\n/**\n * Decodes a string field value.\n *\n * Assumes UTF-8 encoding, handles zero-termination, continuation bytes.\n */\nfunction decodeStringValue(view: DataView, byteOffset: number, byteLength: number) {\n // the array can can be zero terminated, we need to find last non-zero byte\n let length = byteLength;\n for (; length > 0; --length) {\n if (view.getUint8(byteOffset + length - 1) !== 0) {\n break;\n }\n }\n\n if (length === 0) {\n return \"\";\n }\n\n // UTF-8 continuation bytes (deal with garbage)\n if ((view.getUint8(byteOffset + length - 1) & 0x80) !== 0) {\n let start = length;\n for (; start > 0; --start) {\n if ((view.getUint8(byteOffset + start - 1) & 0x40) != 0) {\n break;\n }\n }\n\n if (start == 0) {\n return \"\";\n }\n\n start--;\n const b = view.getUint8(byteOffset + start);\n if ((b & 0xe0) === 0xc0) {\n if (start !== length - 2) {\n length = start;\n }\n } else if ((b & 0xf0) === 0xe0) {\n if (start !== length - 3) {\n length = start;\n }\n } else if ((b & 0xf8) === 0xf0) {\n if (start !== length - 4) {\n length = start;\n }\n }\n }\n\n // create restricted view\n return utf8decoder.decode(new DataView(view.buffer, view.byteOffset + byteOffset, length));\n}\n\n/**\n * Encodes a string field value.\n *\n * The implementation relies on the behavior of `Uint8Array` that is initialized to all zeros\n * and automatically clamps the size of the encoded data to the length of the array.\n */\nfunction encodeStringValue(view: DataView, byteOffset: number, byteLength: number, value: string) {\n utf8encoder.encodeInto(value, new Uint8Array(view.buffer, view.byteOffset + byteOffset, byteLength));\n}\n\n/**\n * Decodes a primitive field value.\n *\n * † Javascript limits integer types to 53-bit representation.\n * Decoding 64-bit integers may result in loss of precision as values\n * that do not fit within the safe integer limit will be represented by\n * floating-point numbers with double precision.\n *\n * ‡ Decoding a character value only makes sense for reading fields that\n * consist of exactly one character, where UTF-8 is essentially ASCII.\n * In practice UTF-8 encoded strings use multiple bytes to represent\n * non-ASCII characters and must be handled in a special way when array\n * of chars is decoded. @see {decodeStringValue}.\n */\nfunction decodePrimitiveValue(field: StructFieldDescriptor, view: DataView, byteOffset: number) {\n switch (field.type) {\n case \"bool\":\n return view.getUint8(byteOffset) !== 0;\n case \"char\":\n return String.fromCharCode(view.getUint8(byteOffset)); // ‡\n case \"int8\":\n return view.getInt8(byteOffset);\n case \"int16\":\n return view.getInt16(byteOffset, true);\n case \"int32\":\n return view.getInt32(byteOffset, true);\n case \"int64\":\n return Number(view.getBigInt64(byteOffset, true)); // †\n case \"uint8\":\n return view.getUint8(byteOffset);\n case \"uint16\":\n return view.getUint16(byteOffset, true);\n case \"uint32\":\n return view.getUint32(byteOffset, true);\n case \"uint64\":\n return Number(view.getBigUint64(byteOffset, true)); // †\n case \"float\":\n return view.getFloat32(byteOffset, true);\n case \"double\":\n return view.getFloat64(byteOffset, true);\n }\n}\n\n/**\n * Encodes a primitive field value.\n */\nfunction encodePrimitiveValue(field: StructFieldDescriptor, view: DataView, byteOffset: number, value: unknown) {\n // convert to numeric representation\n const v =\n value == null ? 0 : typeof value === \"string\" ? (value.length === 0 ? 0 : value.charCodeAt(0)) : Number(value);\n\n switch (field.type) {\n case \"bool\":\n view.setUint8(byteOffset, v);\n break;\n case \"char\":\n view.setUint8(byteOffset, v);\n break;\n case \"int8\":\n view.setInt8(byteOffset, v);\n break;\n case \"int16\":\n view.setInt16(byteOffset, v, true);\n break;\n case \"int32\":\n view.setInt32(byteOffset, v, true);\n break;\n case \"int64\":\n view.setBigInt64(byteOffset, BigInt(v), true);\n break;\n case \"uint8\":\n view.setUint8(byteOffset, v);\n break;\n case \"uint16\":\n view.setUint16(byteOffset, v, true);\n break;\n case \"uint32\":\n view.setUint32(byteOffset, v, true);\n break;\n case \"uint64\":\n view.setBigUint64(byteOffset, BigInt(v), true);\n break;\n case \"float\":\n view.setFloat32(byteOffset, v, true);\n break;\n case \"double\":\n view.setFloat64(byteOffset, v, true);\n break;\n }\n}\n\n/**\n * Decodes a bit-field integer value.\n */\nfunction decodeBitFieldValue(field: StructFieldDescriptor, view: DataView, byteOffset: number) {\n const width = field.bitWidth!;\n const shift = field.bitShift!;\n\n if (field.size === 8) {\n if (width <= 32) {\n // we can fit in 32-bit integer, use hi/lo 32-bit blocks to reconstruct the value\n // 64-bit is stored in LE, so high bits are in the block at a higher address\n const h32 = view.getUint32(byteOffset + 4, true);\n const l32 = view.getUint32(byteOffset, true);\n\n // example: width = 13, shift = 22\n // ........ ........ ........ .....xxx | xxxxxxxx xx...... ........ ........\n // +-------------- h32 --------------+ +-------------- l32 --------------+\n // unsigned\n // l32 >>> shift = 00000000 00000000 000000xx xxxxxxxx\n // h32 << (32 - shift) = ........ ........ ...xxx00 00000000\n // | = ........ ........ 000xxxxx xxxxxxxx\n // & mask = 00000000 00000000 000xxxxx xxxxxxxx\n const v = (shift >= 32 ? h32 >>> (shift - 32) : (l32 >>> shift) | (h32 << (32 - shift))) & bitmask(width);\n return field.type === \"int64\" ? (v << (32 - width)) >> (32 - width) : v;\n } else {\n // we have to resort to unsigned case only due to Javascript limitations\n // that prevent us from performing bit manipulations on 64-bit integers\n const data = view.getBigUint64(byteOffset, true);\n return Number((data >> BigInt(shift)) & (2n ** BigInt(width) - 1n));\n }\n } else {\n // read the block containing the field\n const data =\n field.size === 4\n ? view.getUint32(byteOffset, true)\n : field.size === 2\n ? view.getUint16(byteOffset, true)\n : view.getUint8(byteOffset);\n\n // for unsigned (and boolean) we can just shift and mask\n // note the use of `>>>` unsigned shift operator here\n switch (field.type) {\n case \"bool\":\n case \"uint8\":\n case \"uint16\":\n case \"uint32\": {\n const v = (data >>> shift) & bitmask(width);\n return field.type === \"bool\" ? v !== 0 : v;\n }\n }\n\n // signed integer situation, first shift left to clear high bits and set the sign bit,\n // then shift right, which also clears low bits so masking is not necessary\n // note the use of `<<` and `>>` shift operators here\n // these are overloaded for 32-bit integers\n return (data << (32 - shift - width)) >> (32 - width);\n }\n}\n\n/**\n * Encodes a bit-field integer value.\n */\nfunction encodeBitFieldValue(field: StructFieldDescriptor, view: DataView, byteOffset: number, value: unknown) {\n const width = field.bitWidth!;\n const shift = field.bitShift!;\n\n // convert to numeric representation\n const n = value == null ? 0 : Number(value);\n const overlay = (n: number, v: number, mask: number, shift: number) => (v & ~(mask << shift)) | ((n & mask) << shift);\n\n if (field.size === 8) {\n if (width <= 32) {\n // we can fit in 32-bit integer, use hi/lo 32-bit blocks to overlay the value\n const mask = bitmask(width);\n if (shift >= 32) {\n view.setUint32(byteOffset + 4, overlay(n, view.getUint32(byteOffset + 4, true), mask, shift - 32), true);\n } else if (shift + width <= 32) {\n view.setUint32(byteOffset, overlay(n, view.getUint32(byteOffset, true), mask, shift), true);\n } else {\n // 64-bit is stored in LE, so high bits are in the block at a higher address\n const h32 = view.getUint32(byteOffset + 4, true);\n const l32 = view.getUint32(byteOffset, true);\n const nm = n & mask;\n view.setUint32(byteOffset + 4, (h32 & ~bitmask(shift + width - 32)) | (nm >>> (32 - shift)), true);\n view.setUint32(byteOffset, overlay(nm, l32, bitmask(32 - shift), shift), true);\n }\n } else {\n const data = view.getBigUint64(byteOffset, true);\n const mask = 2n ** BigInt(width) - 1n;\n view.setBigUint64(byteOffset, (data & ~(mask << BigInt(shift))) | ((BigInt(n) & mask) << BigInt(shift)), true);\n }\n } else {\n const mask = bitmask(width);\n switch (field.size) {\n case 4:\n view.setUint32(byteOffset, overlay(n, view.getUint32(byteOffset, true), mask, shift), true);\n break;\n case 2:\n view.setUint16(byteOffset, overlay(n, view.getUint16(byteOffset, true), mask, shift), true);\n break;\n case 1:\n view.setUint8(byteOffset, overlay(n, view.getUint8(byteOffset), mask, shift));\n break;\n }\n }\n}\n\n/** Constructs bitmask of the specified `width` (max 32 bits). */\nconst bitmask = (width: number) => -1 >>> (32 - width);\n\n/** Bytes size of the value type. */\nconst fieldTypeByteSize = {\n bool: 1,\n char: 1,\n int8: 1,\n int16: 2,\n int32: 4,\n int64: 8,\n uint8: 1,\n uint16: 2,\n uint32: 4,\n uint64: 8,\n float: 4,\n double: 8,\n} as const;\n\nconst getFieldType = (type: string): StructFieldType => {\n switch (type) {\n case \"bool\":\n case \"char\":\n case \"int8\":\n case \"int16\":\n case \"int32\":\n case \"int64\":\n case \"uint8\":\n case \"uint16\":\n case \"uint32\":\n case \"uint64\":\n case \"float\":\n case \"double\":\n return type;\n case \"float32\":\n return \"float\";\n case \"float64\":\n return \"double\";\n default:\n return \"ref\";\n }\n};\n\n/** Repository of struct descriptors. */\nexport class StructRepository {\n private readonly unresolved: Array<StructDescriptor> = [];\n\n /** Descriptors in the repository. */\n public readonly descriptors = new Map<string, StructDescriptor>();\n\n /**\n * Computes field bte offsets and returns total packed size in bytes.\n *\n * This method assumes that all fields have resolved external dependencies\n * and will compute byte offsets and bit shifts for bit-field packed fields.\n */\n private static computeFieldOffsets(fields: ReadonlyArray<StructFieldDescriptor>) {\n let offset = 0; // offset in bytes\n let bitBlock = 0; // size in bytes of the current bit-field block\n let bitAvail = 0; // available bits in the current bit-field\n\n for (const field of fields) {\n if (field.bitWidth != null) {\n // current bit-field must be of the same size (except for booleans)\n // and should have sufficient bits remaining\n if ((bitBlock !== field.size && field.type !== \"bool\") || field.bitWidth > bitAvail) {\n // terminate current bit-field\n if (bitBlock > 0) {\n offset += bitBlock;\n }\n\n // start new bit-field block\n bitBlock = field.size;\n bitAvail = bitBlock << 3;\n }\n\n // booleans are \"spliced\" onto current integer block size\n if (field.type === \"bool\") {\n field.size = bitBlock;\n }\n\n field.offset = offset;\n field.bitShift = (bitBlock << 3) - bitAvail;\n bitAvail -= field.bitWidth;\n } else {\n // terminate current bit-field\n if (bitBlock > 0) {\n offset += bitBlock;\n\n // reset bit-field block\n bitBlock = 0;\n bitAvail = 0;\n }\n\n field.offset = offset;\n offset += field.size * (field.arraySize ?? 1);\n }\n }\n\n // account for the terminal bit-field\n return offset + bitBlock;\n }\n\n /**\n * Attempts to finalize any unresolved descriptors with the recently resolved one.\n */\n private resolve(descriptor: StructDescriptor) {\n const resolved: Array<StructDescriptor> = [];\n for (let i = this.unresolved.length - 1; i >= 0; --i) {\n const d = this.unresolved[i]!;\n if (d.unresolved?.has(descriptor.name)) {\n d.unresolved?.delete(descriptor.name);\n d.fields.forEach((_) => {\n if (_.typeRef === descriptor.name) {\n _.typeRef = descriptor;\n _.size = descriptor.size;\n }\n });\n\n // no more unresolved references, we can finalize this descriptor\n if (d.unresolved.size === 0) {\n d.unresolved = undefined;\n d.size = StructRepository.computeFieldOffsets(d.fields);\n this.unresolved.splice(i, 1);\n resolved.push(d);\n }\n }\n }\n\n // resolve recursively\n for (const d of resolved) {\n this.resolve(d);\n }\n }\n\n /**\n * Determines whether type can be transformed, indicating that\n * the parsed type descriptor is present.\n *\n * @param name struct type name\n */\n public canTransform(name: string) {\n const d = this.descriptors.get(name);\n return d != null && d.size > 0;\n }\n\n /**\n * Gets the struct type serialized size in bytes.\n *\n * @param name struct type name\n */\n public getSize(name: string) {\n const size = this.descriptors.get(name)?.size;\n if (size == null || size == 0) {\n throw new Error(`Descriptor for type '${name}' does not exist or is not fully defined`);\n }\n\n return size;\n }\n\n /**\n * Unpacks serialized struct data into JSON object.\n *\n * @param name struct type name\n * @param data serialized binary data\n * @param options additional options\n */\n public unpack(\n name: string,\n data: DataView<ArrayBufferLike> | Uint8Array<ArrayBufferLike>,\n options?: UnpackStructOptions\n ) {\n return unpack(name, data, this, options);\n }\n\n /**\n * Packs JSON object into serialized struct data.\n *\n * @param name struct type name\n * @param value JSON object to pack\n */\n public pack(name: string, value: Record<string, unknown>) {\n return pack(name, value, this);\n }\n\n /**\n * Parses struct schema and adds the resulting descriptor to the repository.\n *\n * The descriptor may not be fully processed if it references other structs that\n * we have not seen yet. Such pending descriptors will be processed automatically,\n * once corresponding structs have been added. This code checks for circular\n * dependencies and will fail when one is detected.\n *\n * @param name struct type name\n * @param data struct schema in UTF-8 encoded binary representation\n * @returns parsed descriptor or `null` if the operation failed\n */\n public add(name: string, data: DataView<ArrayBufferLike> | Uint8Array<ArrayBufferLike>): StructDescriptor | null {\n let decoded: string | undefined;\n try {\n decoded = utf8decoder.decode(data);\n } catch (exception) {\n throw error(\n exception instanceof TypeError\n ? `Failed to parse schema: ${exception.message}`\n : `Failed to parse schema: unknown error`\n );\n }\n\n const fields: Array<StructFieldDescriptor> = [];\n const tokens = decoded\n .split(\";\")\n .map((_) => _.trim())\n .filter((_) => _.length > 0);\n\n const unresolved = new Set<string>();\n for (const token of tokens) {\n // regular expression to parse individual declaration specification\n // returns the following named capture groups:\n // - `enum` -- entire body of non-empty enum specification\n // - `type` -- type name\n // - `id` -- identifier name\n // - `array` -- if present length of the array\n // - `bits` -- if present bit-field width\n //\n // if present `size` and `bits` are mutually exclusive;\n // no attempt is made to allow `enum` specification only for integer data types\n const re =\n /^(?:(?:enum)?\\s*(?:{\\s*}|{(?<enum>(?:\\s*\\w\\s*=\\s*-?\\d+\\s*)(?:,\\s*\\w\\s*=\\s*-?\\d+\\s*)*),?\\s*}))?\\s*(?<type>\\w+)\\s+(?<id>\\w+)\\s*(?:(?:\\[\\s*(?<array>\\d+)\\s*\\])|:\\s*(?<bits>[1-9]\\d?))?$/i;\n\n const m = re.exec(token);\n if (m == null || m.groups == null) {\n throw error(`Failed to parse schema: invalid declaration '${token}'`);\n }\n\n const id = m.groups[\"id\"]!;\n const typeRaw = m.groups[\"type\"]!;\n\n // check for duplicates\n if (fields.some((_) => _.identifier === id)) {\n throw error(`Failed to parse schema: duplicate '${id}' field declaration`);\n }\n\n const field: StructFieldDescriptor = {\n identifier: id,\n type: getFieldType(typeRaw),\n offset: -1,\n size: 0,\n };\n\n if (field.type === \"ref\") {\n field.typeRef = this.descriptors.get(typeRaw);\n if (field.typeRef == null) {\n field.typeRef = typeRaw;\n unresolved.add(typeRaw);\n } else if (field.typeRef.size === 0) {\n throw error(\n `Failed to parse schema: circular dependency detected between '${name}' and '${field.typeRef.name}'`\n );\n } else {\n field.size = field.typeRef.size;\n }\n } else {\n field.size = fieldTypeByteSize[field.type];\n }\n\n // parse and validate bit-field specification\n const bitWidthRaw = m.groups[\"bits\"];\n if (bitWidthRaw != null) {\n field.bitWidth = parseInt(bitWidthRaw, 10);\n if (Number.isNaN(field.bitWidth)) {\n throw error(`Failed to parse schema: non-numeric bit-field width in '${id}' field declaration`);\n }\n\n switch (field.type) {\n case \"bool\":\n if (field.bitWidth !== 1) {\n throw error(`Failed to parse schema: invalid boolean bit-field width '${id}' field declaration`);\n }\n break;\n case \"int8\":\n case \"int16\":\n case \"int32\":\n case \"int64\":\n case \"uint8\":\n case \"uint16\":\n case \"uint32\":\n case \"uint64\":\n if (field.bitWidth < 1 || field.bitWidth > fieldTypeByteSize[field.type] << 3) {\n throw error(`Failed to parse schema: invalid integer bit-field width '${id}' field declaration`);\n }\n break;\n default:\n throw error(`Failed to parse schema: bit-field in non-integer/boolean '${id}' field declaration`);\n }\n }\n\n // parse and validate array size specification\n const arraySizeRaw = m.groups[\"array\"];\n if (arraySizeRaw != null) {\n field.arraySize = parseInt(arraySizeRaw, 10);\n if (Number.isNaN(field.arraySize) || field.arraySize <= 0) {\n throw error(`Failed to parse schema: invalid array size in '${id}' field declaration`);\n }\n }\n\n const enumBodyRaw = m.groups[\"enum\"];\n if (enumBodyRaw) {\n // enum is only allowed for integer declarations\n switch (field.type) {\n case \"int8\":\n case \"int16\":\n case \"int32\":\n case \"int64\":\n case \"uint8\":\n case \"uint16\":\n case \"uint32\":\n case \"uint64\":\n break;\n default:\n throw error(`Failed to parse schema: enum declaration in non-integer '${id}' field declaration`);\n }\n\n // parse enum values\n field.enum = new Map();\n for (const tuple of enumBodyRaw.split(\",\")) {\n const [enumName, valueRaw] = tuple.trim().split(\"=\", 2);\n const enumValue = parseInt(valueRaw!.trim(), 10);\n if (Number.isNaN(enumValue)) {\n throw error(\n `Failed to parse schema: enum declaration contains non-integer value '${valueRaw}' in '${id}' field declaration`\n );\n }\n field.enum.set(enumValue, enumName!);\n }\n }\n\n fields.push(field);\n }\n\n // if this descriptor has external dependencies that we have not observed yet,\n // we cannot map its fields and its packed size is set to zero for now\n const descriptor = {\n name,\n fields,\n size: unresolved.size > 0 ? 0 : StructRepository.computeFieldOffsets(fields),\n unresolved: unresolved.size > 0 ? unresolved : undefined,\n };\n\n this.descriptors.set(name, descriptor);\n\n // if this descriptor is final, see if it resolves any unresolved ones\n if (descriptor.size > 0) {\n this.resolve(descriptor);\n } else {\n this.unresolved.push(descriptor);\n }\n\n return descriptor;\n }\n}\n\n/** Implements {@link DataTransformer} interface for the `struct` serialization protocol. */\nexport class StructDataTransformer implements DataTransformer {\n private readonly repo = new StructRepository();\n\n public inspect(\n source: string,\n name: string,\n type: string,\n metadata?: string | Record<string, unknown>\n ): DataChannel | string | undefined {\n if (name.startsWith(\"/.schema/struct:\")) {\n if (type !== \"structschema\") {\n throw new Error(`Unexpected type '${type}' for struct schema entry`);\n }\n\n return name.substring(16);\n }\n\n if (type.startsWith(\"struct:\")) {\n // strip `[]` array suffix from the type name\n const isArrayType = type.endsWith(\"[]\");\n return {\n source,\n id: name,\n dataType: \"json\",\n publishedDataType: type,\n transformer: this,\n structuredType: {\n name: isArrayType ? type.slice(7, -2) : type.slice(7),\n format: \"struct\",\n isArray: isArrayType,\n },\n metadata,\n };\n }\n\n return undefined;\n }\n\n public schema(typeName: string, value: unknown): void {\n this.repo.add(typeName, toUint8Array(value));\n }\n\n public deserialize(value: unknown, type?: StructuredTypeDescriptor): DataTypeImpl | undefined {\n if (type == null) {\n throw new Error(\n `Transformation requires type to be specified. This situation should not be possible if the transformer is wired correctly.`\n );\n }\n\n if (this.repo.canTransform(type.name)) {\n const buffer = toUint8Array(value);\n\n if (type.isArray) {\n // special case for a top-level array: buffer contains consecutive fixed-size items\n const result: Array<Record<string, unknown>> = [];\n const itemSize = this.repo.getSize(type.name);\n let byteOffset = 0;\n\n while (byteOffset + itemSize <= buffer.byteLength) {\n result.push(\n this.repo.unpack(type.name, new DataView(buffer.buffer, buffer.byteOffset + byteOffset, itemSize), {\n useEnum: true,\n })\n );\n byteOffset += itemSize;\n }\n\n return result;\n }\n\n return this.repo.unpack(type.name, buffer, { useEnum: true });\n }\n\n return undefined;\n }\n\n public serialize(value: unknown, type?: StructuredTypeDescriptor): Uint8Array {\n if (type == null) {\n throw new Error(\n `Transformation requires type to be specified. This situation should not be possible if the transformer is wired correctly.`\n );\n }\n\n if (value == null || typeof value !== \"object\") {\n throw new Error(\"Only JSON objects can be serialized\");\n }\n\n if (this.repo.canTransform(type.name)) {\n if (Array.isArray(value)) {\n // special case for a top-level array: buffer contains consecutive fixed-size items\n const itemSize = this.repo.getSize(type.name);\n const result = new Uint8Array(itemSize * value.length);\n\n for (let i = 0; i < value.length; ++i) {\n const part = this.repo.pack(type.name, value[i] as Record<string, unknown>);\n result.set(part, i * itemSize);\n }\n\n return result;\n }\n\n return this.repo.pack(type.name, value as Record<string, unknown>);\n }\n\n throw new Error(`Struct serialization is not supported for '${type.name}'`);\n }\n\n public canTransform(type: string): boolean {\n return this.repo.canTransform(type);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"struct.mjs","names":["shift","n"],"sources":["../../src/formats/struct.ts"],"sourcesContent":["import { toDataView, toUint8Array } from \"../utils\";\n\nimport type { DataChannel, DataTransformer, DataTypeImpl, StructuredTypeDescriptor } from \"../abstractions\";\n\nconst error = (message: string) => {\n return new Error(message);\n};\n\nexport type StructFieldType =\n | \"ref\"\n | \"bool\"\n | \"char\"\n | \"int8\"\n | \"int16\"\n | \"int32\"\n | \"int64\"\n | \"uint8\"\n | \"uint16\"\n | \"uint32\"\n | \"uint64\"\n | \"float\"\n | \"double\";\n\n/** Describes individual field in {@link StructDescriptor}. */\nexport type StructFieldDescriptor = {\n /** Field identifier */\n identifier: string;\n /** Field value type */\n type: StructFieldType;\n /** Reference for complex (nested) type */\n typeRef?: StructDescriptor | string;\n /** Offset to the packed field data in bytes */\n offset: number;\n /** Size of the packed field data in bytes */\n size: number;\n /** Fixed array size */\n arraySize?: number;\n /** Bit width of the field data (bit-field only) */\n bitWidth?: number;\n /** Bit shift for the field data (bit-field only) */\n bitShift?: number;\n /** Enum specification */\n enum?: Map<number, string>;\n};\n\n/** Describes named struct type. */\nexport type StructDescriptor = {\n /** Struct type name */\n name: string;\n /** Struct fields in packed order */\n fields: ReadonlyArray<StructFieldDescriptor>;\n /** Total packed size in bytes */\n size: number;\n /** Missing dependencies */\n unresolved?: Set<string>;\n};\n\nconst utf8decoder = new TextDecoder(\"utf-8\", {\n // throw TypeError on invalid data instead of silent substitution\n fatal: true,\n});\n\nconst utf8encoder = new TextEncoder();\n\nexport type UnpackStructOptions = {\n /**\n * Indicates that integer numeric values with enum specification should be converted\n * to the corresponding enum string value if possible.\n */\n useEnum?: boolean;\n};\n\n/**\n * Unpacks serialized struct data into JSON object.\n *\n * Implementation of WPILiB packed struct serialization protocol\n * https://github.com/wpilibsuite/allwpilib/blob/main/wpiutil/doc/struct.adoc\n *\n * @param name struct type name\n * @param data serialized binary data\n * @param repository repository of available descriptors\n * @param options additional options\n */\nexport function unpack(\n name: string,\n data: DataView<ArrayBufferLike> | Uint8Array<ArrayBufferLike>,\n repository: StructRepository,\n options?: UnpackStructOptions\n) {\n const descriptor = repository.descriptors.get(name);\n if (descriptor == null) {\n throw error(`Failed to unpack struct data: missing '${name}' type definition`);\n }\n\n // descriptor exists but is not mapped yet due to unresolved dependencies\n if (descriptor.size === 0) {\n throw error(`Failed to unpack struct data: '${name}' type definition has unresolved dependencies`);\n }\n\n const result: Record<string, unknown> = {};\n unpackStruct(result, descriptor, toDataView(data), 0, options?.useEnum ? transformEnums : (_, v) => v);\n return result;\n}\n\n/**\n * Packs JSON object into serialized struct data.\n *\n * @param name struct type name\n * @param value JSON object to pack\n * @param repository repository of available descriptors\n * @returns ArrayBuffer containing serialized data\n */\nexport function pack(name: string, value: Record<string, unknown>, repository: StructRepository) {\n const descriptor = repository.descriptors.get(name);\n if (descriptor == null) {\n throw error(`Failed to pack struct data: missing '${name}' type definition`);\n }\n\n // descriptor exists but is not mapped yet due to unresolved dependencies\n if (descriptor.size === 0) {\n throw error(`Failed to pack struct data: '${name}' type definition has unresolved dependencies`);\n }\n\n const buffer = new ArrayBuffer(descriptor.size);\n const view = new DataView(buffer);\n\n packStruct(value, descriptor, view, 0, transformValue);\n return new Uint8Array(buffer);\n}\n\n/**\n * Transforms field values according to the field descriptor.\n *\n * Handles conversion of enum strings into their numeric representation.\n */\nfunction transformValue(field: StructFieldDescriptor, value: unknown) {\n if (field.enum != null && typeof value === \"string\") {\n for (const [key, v] of field.enum) {\n if (v === value) {\n return key;\n }\n }\n }\n\n return value;\n}\n\n/** Transforms numeric values to enum names for fields that support enums. */\nfunction transformEnums(field: StructFieldDescriptor, value: unknown) {\n if (field.enum != null && typeof value === \"number\") {\n const enumName = field.enum.get(value);\n if (enumName != null) {\n return enumName;\n }\n }\n\n return value;\n}\n\n/**\n * Unpacks data per descriptor specification and populates `sink` placeholder instance.\n *\n * @param sink target object to populate with parsed data\n * @param descriptor struct type descriptor\n * @param view source buffer view\n * @param byteOffset offset in bytes within `view`\n * @param transformer primitive field value transformer\n */\nfunction unpackStruct(\n sink: Record<string, unknown>,\n descriptor: StructDescriptor,\n view: DataView,\n byteOffset: number,\n transformer: (field: StructFieldDescriptor, value: unknown) => unknown\n) {\n for (const field of descriptor.fields) {\n if (field.type === \"ref\") {\n // nested structure\n if (field.typeRef == null || typeof field.typeRef !== \"object\") {\n throw error(`Failed to unpack struct data: field '${field.identifier}' references unresolved type`);\n }\n\n // array of nested structures\n if (field.arraySize != null) {\n const result: Array<Record<string, unknown>> = [];\n for (let i = 0; i < field.arraySize; ++i) {\n const v: Record<string, unknown> = {};\n unpackStruct(v, field.typeRef, view, byteOffset + field.offset + i * field.size, transformer);\n result.push(v);\n }\n sink[field.identifier] = result;\n } else {\n const result: Record<string, unknown> = {};\n unpackStruct(result, field.typeRef, view, byteOffset + field.offset, transformer);\n sink[field.identifier] = result;\n }\n } else if (field.arraySize != null) {\n if (field.type === \"char\") {\n // array of chars is UTF-8 encoded string\n sink[field.identifier] = transformer(\n field,\n decodeStringValue(view, byteOffset + field.offset, field.arraySize)\n );\n } else {\n // array of booleans or numeric values\n const result: Array<unknown> = [];\n for (let i = 0; i < field.arraySize; ++i) {\n result.push(\n transformer(field, decodePrimitiveValue(field, view, byteOffset + field.offset + i * field.size))\n );\n }\n }\n } else if (field.bitWidth != null) {\n sink[field.identifier] = transformer(field, decodeBitFieldValue(field, view, byteOffset + field.offset));\n } else {\n sink[field.identifier] = transformer(field, decodePrimitiveValue(field, view, byteOffset + field.offset));\n }\n }\n}\n\n/**\n * Packs data per descriptor specification.\n *\n * @param source source object to pack\n * @param descriptor struct type descriptor\n * @param view target buffer view\n * @param byteOffset offset in bytes within `view`\n * @param transformer primitive field value transformer\n */\nfunction packStruct(\n source: Record<string, unknown>,\n descriptor: StructDescriptor,\n view: DataView,\n byteOffset: number,\n transformer: (field: StructFieldDescriptor, value: unknown) => unknown\n) {\n for (const field of descriptor.fields) {\n const value = source[field.identifier];\n\n if (field.type === \"ref\") {\n // nested structure\n if (field.typeRef == null || typeof field.typeRef !== \"object\") {\n throw error(`Failed to pack struct data: field '${field.identifier}' references unresolved type`);\n }\n\n // array of nested structures\n if (field.arraySize != null) {\n if (!Array.isArray(value) || value.length != field.arraySize) {\n throw error(\n `Failed to pack struct data: field '${field.identifier}' must be an array of length ${field.arraySize}`\n );\n }\n\n for (let i = 0; i < field.arraySize; ++i) {\n packStruct(value[i], field.typeRef, view, byteOffset + field.offset + i * field.size, transformer);\n }\n } else {\n packStruct(\n (value ?? {}) as Record<string, unknown>,\n field.typeRef,\n view,\n byteOffset + field.offset,\n transformer\n );\n }\n } else if (field.arraySize != null) {\n if (field.type === \"char\") {\n // array of chars is UTF-8 encoded string\n encodeStringValue(\n view,\n byteOffset + field.offset,\n field.arraySize,\n (transformer(field, value) ?? \"\") as string\n );\n } else {\n // array of booleans or numeric values\n for (let i = 0; i < field.arraySize; ++i) {\n encodePrimitiveValue(field, view, byteOffset + field.offset + i * field.size, transformer(field, value));\n }\n }\n } else if (field.bitWidth != null) {\n encodeBitFieldValue(field, view, byteOffset + field.offset, transformer(field, value));\n } else {\n encodePrimitiveValue(field, view, byteOffset + field.offset, transformer(field, value));\n }\n }\n}\n\n/**\n * Decodes a string field value.\n *\n * Assumes UTF-8 encoding, handles zero-termination, continuation bytes.\n */\nfunction decodeStringValue(view: DataView, byteOffset: number, byteLength: number) {\n // the array can can be zero terminated, we need to find last non-zero byte\n let length = byteLength;\n for (; length > 0; --length) {\n if (view.getUint8(byteOffset + length - 1) !== 0) {\n break;\n }\n }\n\n if (length === 0) {\n return \"\";\n }\n\n // UTF-8 continuation bytes (deal with garbage)\n if ((view.getUint8(byteOffset + length - 1) & 0x80) !== 0) {\n let start = length;\n for (; start > 0; --start) {\n if ((view.getUint8(byteOffset + start - 1) & 0x40) != 0) {\n break;\n }\n }\n\n if (start == 0) {\n return \"\";\n }\n\n start--;\n const b = view.getUint8(byteOffset + start);\n if ((b & 0xe0) === 0xc0) {\n if (start !== length - 2) {\n length = start;\n }\n } else if ((b & 0xf0) === 0xe0) {\n if (start !== length - 3) {\n length = start;\n }\n } else if ((b & 0xf8) === 0xf0) {\n if (start !== length - 4) {\n length = start;\n }\n }\n }\n\n // create restricted view\n return utf8decoder.decode(new DataView(view.buffer, view.byteOffset + byteOffset, length));\n}\n\n/**\n * Encodes a string field value.\n *\n * The implementation relies on the behavior of `Uint8Array` that is initialized to all zeros\n * and automatically clamps the size of the encoded data to the length of the array.\n */\nfunction encodeStringValue(view: DataView, byteOffset: number, byteLength: number, value: string) {\n utf8encoder.encodeInto(value, new Uint8Array(view.buffer, view.byteOffset + byteOffset, byteLength));\n}\n\n/**\n * Decodes a primitive field value.\n *\n * † Javascript limits integer types to 53-bit representation.\n * Decoding 64-bit integers may result in loss of precision as values\n * that do not fit within the safe integer limit will be represented by\n * floating-point numbers with double precision.\n *\n * ‡ Decoding a character value only makes sense for reading fields that\n * consist of exactly one character, where UTF-8 is essentially ASCII.\n * In practice UTF-8 encoded strings use multiple bytes to represent\n * non-ASCII characters and must be handled in a special way when array\n * of chars is decoded. @see {decodeStringValue}.\n */\nfunction decodePrimitiveValue(field: StructFieldDescriptor, view: DataView, byteOffset: number) {\n switch (field.type) {\n case \"bool\":\n return view.getUint8(byteOffset) !== 0;\n case \"char\":\n return String.fromCharCode(view.getUint8(byteOffset)); // ‡\n case \"int8\":\n return view.getInt8(byteOffset);\n case \"int16\":\n return view.getInt16(byteOffset, true);\n case \"int32\":\n return view.getInt32(byteOffset, true);\n case \"int64\":\n return Number(view.getBigInt64(byteOffset, true)); // †\n case \"uint8\":\n return view.getUint8(byteOffset);\n case \"uint16\":\n return view.getUint16(byteOffset, true);\n case \"uint32\":\n return view.getUint32(byteOffset, true);\n case \"uint64\":\n return Number(view.getBigUint64(byteOffset, true)); // †\n case \"float\":\n return view.getFloat32(byteOffset, true);\n case \"double\":\n return view.getFloat64(byteOffset, true);\n }\n}\n\n/**\n * Encodes a primitive field value.\n */\nfunction encodePrimitiveValue(field: StructFieldDescriptor, view: DataView, byteOffset: number, value: unknown) {\n // convert to numeric representation\n const v =\n value == null ? 0 : typeof value === \"string\" ? (value.length === 0 ? 0 : value.charCodeAt(0)) : Number(value);\n\n switch (field.type) {\n case \"bool\":\n view.setUint8(byteOffset, v);\n break;\n case \"char\":\n view.setUint8(byteOffset, v);\n break;\n case \"int8\":\n view.setInt8(byteOffset, v);\n break;\n case \"int16\":\n view.setInt16(byteOffset, v, true);\n break;\n case \"int32\":\n view.setInt32(byteOffset, v, true);\n break;\n case \"int64\":\n view.setBigInt64(byteOffset, BigInt(v), true);\n break;\n case \"uint8\":\n view.setUint8(byteOffset, v);\n break;\n case \"uint16\":\n view.setUint16(byteOffset, v, true);\n break;\n case \"uint32\":\n view.setUint32(byteOffset, v, true);\n break;\n case \"uint64\":\n view.setBigUint64(byteOffset, BigInt(v), true);\n break;\n case \"float\":\n view.setFloat32(byteOffset, v, true);\n break;\n case \"double\":\n view.setFloat64(byteOffset, v, true);\n break;\n }\n}\n\n/**\n * Decodes a bit-field integer value.\n */\nfunction decodeBitFieldValue(field: StructFieldDescriptor, view: DataView, byteOffset: number) {\n const width = field.bitWidth!;\n const shift = field.bitShift!;\n\n if (field.size === 8) {\n if (width <= 32) {\n // we can fit in 32-bit integer, use hi/lo 32-bit blocks to reconstruct the value\n // 64-bit is stored in LE, so high bits are in the block at a higher address\n const h32 = view.getUint32(byteOffset + 4, true);\n const l32 = view.getUint32(byteOffset, true);\n\n // example: width = 13, shift = 22\n // ........ ........ ........ .....xxx | xxxxxxxx xx...... ........ ........\n // +-------------- h32 --------------+ +-------------- l32 --------------+\n // unsigned\n // l32 >>> shift = 00000000 00000000 000000xx xxxxxxxx\n // h32 << (32 - shift) = ........ ........ ...xxx00 00000000\n // | = ........ ........ 000xxxxx xxxxxxxx\n // & mask = 00000000 00000000 000xxxxx xxxxxxxx\n const v = (shift >= 32 ? h32 >>> (shift - 32) : (l32 >>> shift) | (h32 << (32 - shift))) & bitmask(width);\n return field.type === \"int64\" ? (v << (32 - width)) >> (32 - width) : v;\n } else {\n // we have to resort to unsigned case only due to Javascript limitations\n // that prevent us from performing bit manipulations on 64-bit integers\n const data = view.getBigUint64(byteOffset, true);\n return Number((data >> BigInt(shift)) & (2n ** BigInt(width) - 1n));\n }\n } else {\n // read the block containing the field\n const data =\n field.size === 4\n ? view.getUint32(byteOffset, true)\n : field.size === 2\n ? view.getUint16(byteOffset, true)\n : view.getUint8(byteOffset);\n\n // for unsigned (and boolean) we can just shift and mask\n // note the use of `>>>` unsigned shift operator here\n switch (field.type) {\n case \"bool\":\n case \"uint8\":\n case \"uint16\":\n case \"uint32\": {\n const v = (data >>> shift) & bitmask(width);\n return field.type === \"bool\" ? v !== 0 : v;\n }\n }\n\n // signed integer situation, first shift left to clear high bits and set the sign bit,\n // then shift right, which also clears low bits so masking is not necessary\n // note the use of `<<` and `>>` shift operators here\n // these are overloaded for 32-bit integers\n return (data << (32 - shift - width)) >> (32 - width);\n }\n}\n\n/**\n * Encodes a bit-field integer value.\n */\nfunction encodeBitFieldValue(field: StructFieldDescriptor, view: DataView, byteOffset: number, value: unknown) {\n const width = field.bitWidth!;\n const shift = field.bitShift!;\n\n // convert to numeric representation\n const n = value == null ? 0 : Number(value);\n const overlay = (n: number, v: number, mask: number, shift: number) => (v & ~(mask << shift)) | ((n & mask) << shift);\n\n if (field.size === 8) {\n if (width <= 32) {\n // we can fit in 32-bit integer, use hi/lo 32-bit blocks to overlay the value\n const mask = bitmask(width);\n if (shift >= 32) {\n view.setUint32(byteOffset + 4, overlay(n, view.getUint32(byteOffset + 4, true), mask, shift - 32), true);\n } else if (shift + width <= 32) {\n view.setUint32(byteOffset, overlay(n, view.getUint32(byteOffset, true), mask, shift), true);\n } else {\n // 64-bit is stored in LE, so high bits are in the block at a higher address\n const h32 = view.getUint32(byteOffset + 4, true);\n const l32 = view.getUint32(byteOffset, true);\n const nm = n & mask;\n view.setUint32(byteOffset + 4, (h32 & ~bitmask(shift + width - 32)) | (nm >>> (32 - shift)), true);\n view.setUint32(byteOffset, overlay(nm, l32, bitmask(32 - shift), shift), true);\n }\n } else {\n const data = view.getBigUint64(byteOffset, true);\n const mask = 2n ** BigInt(width) - 1n;\n view.setBigUint64(byteOffset, (data & ~(mask << BigInt(shift))) | ((BigInt(n) & mask) << BigInt(shift)), true);\n }\n } else {\n const mask = bitmask(width);\n switch (field.size) {\n case 4:\n view.setUint32(byteOffset, overlay(n, view.getUint32(byteOffset, true), mask, shift), true);\n break;\n case 2:\n view.setUint16(byteOffset, overlay(n, view.getUint16(byteOffset, true), mask, shift), true);\n break;\n case 1:\n view.setUint8(byteOffset, overlay(n, view.getUint8(byteOffset), mask, shift));\n break;\n }\n }\n}\n\n/** Constructs bitmask of the specified `width` (max 32 bits). */\nconst bitmask = (width: number) => -1 >>> (32 - width);\n\n/** Bytes size of the value type. */\nconst fieldTypeByteSize = {\n bool: 1,\n char: 1,\n int8: 1,\n int16: 2,\n int32: 4,\n int64: 8,\n uint8: 1,\n uint16: 2,\n uint32: 4,\n uint64: 8,\n float: 4,\n double: 8,\n} as const;\n\nconst getFieldType = (type: string): StructFieldType => {\n switch (type) {\n case \"bool\":\n case \"char\":\n case \"int8\":\n case \"int16\":\n case \"int32\":\n case \"int64\":\n case \"uint8\":\n case \"uint16\":\n case \"uint32\":\n case \"uint64\":\n case \"float\":\n case \"double\":\n return type;\n case \"float32\":\n return \"float\";\n case \"float64\":\n return \"double\";\n default:\n return \"ref\";\n }\n};\n\n/** Repository of struct descriptors. */\nexport class StructRepository {\n private readonly unresolved: Array<StructDescriptor> = [];\n\n /** Descriptors in the repository. */\n public readonly descriptors = new Map<string, StructDescriptor>();\n\n /**\n * Computes field bte offsets and returns total packed size in bytes.\n *\n * This method assumes that all fields have resolved external dependencies\n * and will compute byte offsets and bit shifts for bit-field packed fields.\n */\n private static computeFieldOffsets(fields: ReadonlyArray<StructFieldDescriptor>) {\n let offset = 0; // offset in bytes\n let bitBlock = 0; // size in bytes of the current bit-field block\n let bitAvail = 0; // available bits in the current bit-field\n\n for (const field of fields) {\n if (field.bitWidth != null) {\n // current bit-field must be of the same size (except for booleans)\n // and should have sufficient bits remaining\n if ((bitBlock !== field.size && field.type !== \"bool\") || field.bitWidth > bitAvail) {\n // terminate current bit-field\n if (bitBlock > 0) {\n offset += bitBlock;\n }\n\n // start new bit-field block\n bitBlock = field.size;\n bitAvail = bitBlock << 3;\n }\n\n // booleans are \"spliced\" onto current integer block size\n if (field.type === \"bool\") {\n field.size = bitBlock;\n }\n\n field.offset = offset;\n field.bitShift = (bitBlock << 3) - bitAvail;\n bitAvail -= field.bitWidth;\n } else {\n // terminate current bit-field\n if (bitBlock > 0) {\n offset += bitBlock;\n\n // reset bit-field block\n bitBlock = 0;\n bitAvail = 0;\n }\n\n field.offset = offset;\n offset += field.size * (field.arraySize ?? 1);\n }\n }\n\n // account for the terminal bit-field\n return offset + bitBlock;\n }\n\n /**\n * Attempts to finalize any unresolved descriptors with the recently resolved one.\n */\n private resolve(descriptor: StructDescriptor) {\n const resolved: Array<StructDescriptor> = [];\n for (let i = this.unresolved.length - 1; i >= 0; --i) {\n const d = this.unresolved[i]!;\n if (d.unresolved?.has(descriptor.name)) {\n d.unresolved?.delete(descriptor.name);\n d.fields.forEach((_) => {\n if (_.typeRef === descriptor.name) {\n _.typeRef = descriptor;\n _.size = descriptor.size;\n }\n });\n\n // no more unresolved references, we can finalize this descriptor\n if (d.unresolved.size === 0) {\n d.unresolved = undefined;\n d.size = StructRepository.computeFieldOffsets(d.fields);\n this.unresolved.splice(i, 1);\n resolved.push(d);\n }\n }\n }\n\n // resolve recursively\n for (const d of resolved) {\n this.resolve(d);\n }\n }\n\n /**\n * Determines whether type can be transformed, indicating that\n * the parsed type descriptor is present.\n *\n * @param name struct type name\n */\n public canTransform(name: string) {\n const d = this.descriptors.get(name);\n return d != null && d.size > 0;\n }\n\n /**\n * Gets the struct type serialized size in bytes.\n *\n * @param name struct type name\n */\n public getSize(name: string) {\n const size = this.descriptors.get(name)?.size;\n if (size == null || size == 0) {\n throw new Error(`Descriptor for type '${name}' does not exist or is not fully defined`);\n }\n\n return size;\n }\n\n /**\n * Unpacks serialized struct data into JSON object.\n *\n * @param name struct type name\n * @param data serialized binary data\n * @param options additional options\n */\n public unpack(\n name: string,\n data: DataView<ArrayBufferLike> | Uint8Array<ArrayBufferLike>,\n options?: UnpackStructOptions\n ) {\n return unpack(name, data, this, options);\n }\n\n /**\n * Packs JSON object into serialized struct data.\n *\n * @param name struct type name\n * @param value JSON object to pack\n */\n public pack(name: string, value: Record<string, unknown>) {\n return pack(name, value, this);\n }\n\n /**\n * Parses struct schema and adds the resulting descriptor to the repository.\n *\n * The descriptor may not be fully processed if it references other structs that\n * we have not seen yet. Such pending descriptors will be processed automatically,\n * once corresponding structs have been added. This code checks for circular\n * dependencies and will fail when one is detected.\n *\n * @param name struct type name\n * @param data struct schema in UTF-8 encoded binary representation\n * @returns parsed descriptor or `null` if the operation failed\n */\n public add(name: string, data: DataView<ArrayBufferLike> | Uint8Array<ArrayBufferLike>): StructDescriptor | null {\n let decoded: string | undefined;\n try {\n decoded = utf8decoder.decode(data);\n } catch (exception) {\n throw error(\n exception instanceof TypeError\n ? `Failed to parse schema: ${exception.message}`\n : `Failed to parse schema: unknown error`\n );\n }\n\n const fields: Array<StructFieldDescriptor> = [];\n const tokens = decoded\n .split(\";\")\n .map((_) => _.trim())\n .filter((_) => _.length > 0);\n\n const unresolved = new Set<string>();\n for (const token of tokens) {\n // regular expression to parse individual declaration specification\n // returns the following named capture groups:\n // - `enum` -- entire body of non-empty enum specification\n // - `type` -- type name\n // - `id` -- identifier name\n // - `array` -- if present length of the array\n // - `bits` -- if present bit-field width\n //\n // if present `size` and `bits` are mutually exclusive;\n // no attempt is made to allow `enum` specification only for integer data types\n const re =\n /^(?:(?:enum)?\\s*(?:{\\s*}|{(?<enum>(?:\\s*\\w\\s*=\\s*-?\\d+\\s*)(?:,\\s*\\w\\s*=\\s*-?\\d+\\s*)*),?\\s*}))?\\s*(?<type>\\w+)\\s+(?<id>\\w+)\\s*(?:(?:\\[\\s*(?<array>\\d+)\\s*\\])|:\\s*(?<bits>[1-9]\\d?))?$/i;\n\n const m = re.exec(token);\n if (m == null || m.groups == null) {\n throw error(`Failed to parse schema: invalid declaration '${token}'`);\n }\n\n const id = m.groups[\"id\"]!;\n const typeRaw = m.groups[\"type\"]!;\n\n // check for duplicates\n if (fields.some((_) => _.identifier === id)) {\n throw error(`Failed to parse schema: duplicate '${id}' field declaration`);\n }\n\n const field: StructFieldDescriptor = {\n identifier: id,\n type: getFieldType(typeRaw),\n offset: -1,\n size: 0,\n };\n\n if (field.type === \"ref\") {\n field.typeRef = this.descriptors.get(typeRaw);\n if (field.typeRef == null) {\n field.typeRef = typeRaw;\n unresolved.add(typeRaw);\n } else if (field.typeRef.size === 0) {\n throw error(\n `Failed to parse schema: circular dependency detected between '${name}' and '${field.typeRef.name}'`\n );\n } else {\n field.size = field.typeRef.size;\n }\n } else {\n field.size = fieldTypeByteSize[field.type];\n }\n\n // parse and validate bit-field specification\n const bitWidthRaw = m.groups[\"bits\"];\n if (bitWidthRaw != null) {\n field.bitWidth = parseInt(bitWidthRaw, 10);\n if (Number.isNaN(field.bitWidth)) {\n throw error(`Failed to parse schema: non-numeric bit-field width in '${id}' field declaration`);\n }\n\n switch (field.type) {\n case \"bool\":\n if (field.bitWidth !== 1) {\n throw error(`Failed to parse schema: invalid boolean bit-field width '${id}' field declaration`);\n }\n break;\n case \"int8\":\n case \"int16\":\n case \"int32\":\n case \"int64\":\n case \"uint8\":\n case \"uint16\":\n case \"uint32\":\n case \"uint64\":\n if (field.bitWidth < 1 || field.bitWidth > fieldTypeByteSize[field.type] << 3) {\n throw error(`Failed to parse schema: invalid integer bit-field width '${id}' field declaration`);\n }\n break;\n default:\n throw error(`Failed to parse schema: bit-field in non-integer/boolean '${id}' field declaration`);\n }\n }\n\n // parse and validate array size specification\n const arraySizeRaw = m.groups[\"array\"];\n if (arraySizeRaw != null) {\n field.arraySize = parseInt(arraySizeRaw, 10);\n if (Number.isNaN(field.arraySize) || field.arraySize <= 0) {\n throw error(`Failed to parse schema: invalid array size in '${id}' field declaration`);\n }\n }\n\n const enumBodyRaw = m.groups[\"enum\"];\n if (enumBodyRaw) {\n // enum is only allowed for integer declarations\n switch (field.type) {\n case \"int8\":\n case \"int16\":\n case \"int32\":\n case \"int64\":\n case \"uint8\":\n case \"uint16\":\n case \"uint32\":\n case \"uint64\":\n break;\n default:\n throw error(`Failed to parse schema: enum declaration in non-integer '${id}' field declaration`);\n }\n\n // parse enum values\n field.enum = new Map();\n for (const tuple of enumBodyRaw.split(\",\")) {\n const [enumName, valueRaw] = tuple.trim().split(\"=\", 2);\n const enumValue = parseInt(valueRaw!.trim(), 10);\n if (Number.isNaN(enumValue)) {\n throw error(\n `Failed to parse schema: enum declaration contains non-integer value '${valueRaw}' in '${id}' field declaration`\n );\n }\n field.enum.set(enumValue, enumName!);\n }\n }\n\n fields.push(field);\n }\n\n // if this descriptor has external dependencies that we have not observed yet,\n // we cannot map its fields and its packed size is set to zero for now\n const descriptor = {\n name,\n fields,\n size: unresolved.size > 0 ? 0 : StructRepository.computeFieldOffsets(fields),\n unresolved: unresolved.size > 0 ? unresolved : undefined,\n };\n\n this.descriptors.set(name, descriptor);\n\n // if this descriptor is final, see if it resolves any unresolved ones\n if (descriptor.size > 0) {\n this.resolve(descriptor);\n } else {\n this.unresolved.push(descriptor);\n }\n\n return descriptor;\n }\n}\n\n/** Implements {@link DataTransformer} interface for the `struct` serialization protocol. */\nexport class StructDataTransformer implements DataTransformer {\n private readonly repo = new StructRepository();\n\n public inspect(\n source: string,\n name: string,\n type: string,\n metadata?: string | Record<string, unknown>\n ): DataChannel | string | undefined {\n if (name.startsWith(\"/.schema/struct:\")) {\n if (type !== \"structschema\") {\n throw new Error(`Unexpected type '${type}' for struct schema entry`);\n }\n\n return name.substring(16);\n }\n\n if (type.startsWith(\"struct:\")) {\n // strip `[]` array suffix from the type name\n const isArrayType = type.endsWith(\"[]\");\n return {\n source,\n id: name,\n dataType: \"json\",\n publishedDataType: type,\n transformer: this,\n structuredType: {\n name: isArrayType ? type.slice(7, -2) : type.slice(7),\n format: \"struct\",\n isArray: isArrayType,\n },\n metadata,\n };\n }\n\n return undefined;\n }\n\n public schema(typeName: string, value: unknown): void {\n this.repo.add(typeName, toUint8Array(value));\n }\n\n public deserialize(value: unknown, type?: StructuredTypeDescriptor): DataTypeImpl | undefined {\n if (type == null) {\n throw new Error(\n `Transformation requires type to be specified. This situation should not be possible if the transformer is wired correctly.`\n );\n }\n\n if (this.repo.canTransform(type.name)) {\n const buffer = toUint8Array(value);\n\n if (type.isArray) {\n // special case for a top-level array: buffer contains consecutive fixed-size items\n const result: Array<Record<string, unknown>> = [];\n const itemSize = this.repo.getSize(type.name);\n let byteOffset = 0;\n\n while (byteOffset + itemSize <= buffer.byteLength) {\n result.push(\n this.repo.unpack(type.name, new DataView(buffer.buffer, buffer.byteOffset + byteOffset, itemSize), {\n useEnum: true,\n })\n );\n byteOffset += itemSize;\n }\n\n return result;\n }\n\n return this.repo.unpack(type.name, buffer, { useEnum: true });\n }\n\n return undefined;\n }\n\n public serialize(value: unknown, type?: StructuredTypeDescriptor): Uint8Array {\n if (type == null) {\n throw new Error(\n `Transformation requires type to be specified. This situation should not be possible if the transformer is wired correctly.`\n );\n }\n\n if (value == null || typeof value !== \"object\") {\n throw new Error(\"Only JSON objects can be serialized\");\n }\n\n if (this.repo.canTransform(type.name)) {\n if (Array.isArray(value)) {\n // special case for a top-level array: buffer contains consecutive fixed-size items\n const itemSize = this.repo.getSize(type.name);\n const result = new Uint8Array(itemSize * value.length);\n\n for (let i = 0; i < value.length; ++i) {\n const part = this.repo.pack(type.name, value[i] as Record<string, unknown>);\n result.set(part, i * itemSize);\n }\n\n return result;\n }\n\n return this.repo.pack(type.name, value as Record<string, unknown>);\n }\n\n throw new Error(`Struct serialization is not supported for '${type.name}'`);\n }\n\n public canTransform(type: string): boolean {\n return this.repo.canTransform(type);\n }\n}\n"],"mappings":"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"}