Skip to content

Commit c203b4c

Browse files
committed
Convert CBOR functions to typescript
1 parent 39a7484 commit c203b4c

File tree

3 files changed

+151
-138
lines changed

3 files changed

+151
-138
lines changed

src/util/cborTypedArrayTags.js

Lines changed: 0 additions & 115 deletions
This file was deleted.

src/util/cborTypedArrayTags.ts

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
type TypedArrayConstructor =
2+
| Uint8ArrayConstructor
3+
| Uint16ArrayConstructor
4+
| Uint32ArrayConstructor
5+
| Int8ArrayConstructor
6+
| Int16ArrayConstructor
7+
| Int32ArrayConstructor
8+
| Float32ArrayConstructor
9+
| Float64ArrayConstructor;
10+
11+
// Type for functions that convert arrays
12+
type ArrayConverter = (bytes: Uint8Array) => number[];
13+
14+
const UPPER32 = Math.pow(2, 32);
15+
16+
let warnedPrecision = false;
17+
function warnPrecision() {
18+
if (!warnedPrecision) {
19+
warnedPrecision = true;
20+
console.warn(
21+
'CBOR 64-bit integer array values may lose precision. No further warnings.'
22+
);
23+
}
24+
}
25+
26+
/**
27+
* Unpack 64-bit unsigned integer from byte array.
28+
* @param {Uint8Array} bytes
29+
*/
30+
function decodeUint64LE(bytes: Uint8Array) {
31+
warnPrecision();
32+
33+
const byteLen = bytes.byteLength;
34+
const offset = bytes.byteOffset;
35+
const arrLen = byteLen / 8;
36+
37+
const buffer = bytes.buffer.slice(offset, offset + byteLen);
38+
const uint32View = new Uint32Array(buffer);
39+
40+
const arr = new Array<number>(arrLen);
41+
for (let i = 0; i < arrLen; i++) {
42+
const si = i * 2;
43+
const lo = uint32View[si];
44+
const hi = uint32View[si + 1];
45+
arr[i] = lo + UPPER32 * hi;
46+
}
47+
48+
return arr;
49+
}
50+
51+
/**
52+
* Unpack 64-bit signed integer from byte array.
53+
* @param {Uint8Array} bytes
54+
*/
55+
function decodeInt64LE(bytes: Uint8Array) {
56+
warnPrecision();
57+
58+
const byteLen = bytes.byteLength;
59+
const offset = bytes.byteOffset;
60+
const arrLen = byteLen / 8;
61+
62+
const buffer = bytes.buffer.slice(offset, offset + byteLen);
63+
const uint32View = new Uint32Array(buffer);
64+
const int32View = new Int32Array(buffer);
65+
66+
const arr = new Array<number>(arrLen);
67+
for (let i = 0; i < arrLen; i++) {
68+
const si = i * 2;
69+
const lo = uint32View[si];
70+
const hi = int32View[si + 1];
71+
arr[i] = lo + UPPER32 * hi;
72+
}
73+
74+
return arr;
75+
}
76+
77+
/**
78+
* Unpack typed array from byte array.
79+
* @param {Uint8Array} bytes
80+
* @param {ArrayConstructor} ArrayType - Desired output array type
81+
*/
82+
function decodeNativeArray<T extends TypedArrayConstructor>(bytes: Uint8Array, ArrayType: T): T['prototype'] {
83+
const byteLen = bytes.byteLength;
84+
const offset = bytes.byteOffset;
85+
const buffer = bytes.buffer.slice(offset, offset + byteLen);
86+
return new ArrayType(buffer);
87+
}
88+
89+
/**
90+
* Supports a subset of draft CBOR typed array tags:
91+
* <https://tools.ietf.org/html/draft-ietf-cbor-array-tags-00>
92+
*
93+
* Only supports little-endian tags for now.
94+
*/
95+
const nativeArrayTypes = {
96+
64: Uint8Array,
97+
69: Uint16Array,
98+
70: Uint32Array,
99+
72: Int8Array,
100+
77: Int16Array,
101+
78: Int32Array,
102+
85: Float32Array,
103+
86: Float64Array
104+
} as const;
105+
106+
/**
107+
* We can also decode 64-bit integer arrays, since ROS has these types.
108+
*/
109+
const conversionArrayTypes: Record<number, ArrayConverter> = {
110+
71: decodeUint64LE,
111+
79: decodeInt64LE
112+
} as const;
113+
114+
/**
115+
* Handle CBOR typed array tags during decoding.
116+
* @param {Uint8Array} data
117+
* @param tag
118+
*/
119+
export default function cborTypedArrayTagger(data: Uint8Array, tag: keyof typeof nativeArrayTypes) {
120+
if (tag in nativeArrayTypes) {
121+
const arrayType = nativeArrayTypes[tag];
122+
return decodeNativeArray(data, arrayType);
123+
}
124+
if (tag in conversionArrayTypes) {
125+
return conversionArrayTypes[tag](data);
126+
}
127+
return data;
128+
}

test/cbor.test.js renamed to test/cbor.test.ts

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import CBOR from 'cbor-js';
33
import cborTypedArrayTagger from '../src/util/cborTypedArrayTags.js';
44

55
/** Convert hex string to ArrayBuffer. */
6-
function hexToBuffer(hex) {
7-
var tokens = hex.match(/[0-9a-fA-F]{2}/gi);
8-
var arr = tokens.map(function(t) {
6+
function hexToBuffer(hex: string) {
7+
const tokens = hex.match(/[0-9a-fA-F]{2}/gi) ?? [];
8+
const arr = tokens.map((t: string) => {
99
return parseInt(t, 16);
1010
});
1111
return new Uint8Array(arr).buffer;
@@ -15,8 +15,8 @@ function hexToBuffer(hex) {
1515
describe('CBOR Typed Array Tagger', function() {
1616

1717
it('should convert tagged Uint16Array', function() {
18-
var data = hexToBuffer('d84546010002000300');
19-
var msg = CBOR.decode(data, cborTypedArrayTagger);
18+
const data = hexToBuffer('d84546010002000300');
19+
const msg = CBOR.decode(data, cborTypedArrayTagger);
2020

2121
expect(msg).to.be.a('Uint16Array');
2222
expect(msg).to.have.lengthOf(3);
@@ -26,8 +26,8 @@ describe('CBOR Typed Array Tagger', function() {
2626
});
2727

2828
it('should convert tagged Uint32Array', function() {
29-
var data = hexToBuffer('d8464c010000000200000003000000');
30-
var msg = CBOR.decode(data, cborTypedArrayTagger);
29+
const data = hexToBuffer('d8464c010000000200000003000000');
30+
const msg = CBOR.decode(data, cborTypedArrayTagger);
3131

3232
expect(msg).to.be.a('Uint32Array');
3333
expect(msg).to.have.lengthOf(3);
@@ -37,8 +37,8 @@ describe('CBOR Typed Array Tagger', function() {
3737
});
3838

3939
it('should convert tagged Uint64Array', function() {
40-
var data = hexToBuffer('d8475818010000000000000002000000000000000300000000000000');
41-
var msg = CBOR.decode(data, cborTypedArrayTagger);
40+
const data = hexToBuffer('d8475818010000000000000002000000000000000300000000000000');
41+
const msg = CBOR.decode(data, cborTypedArrayTagger);
4242

4343
expect(msg).to.be.a('Array');
4444
expect(msg).to.have.lengthOf(3);
@@ -48,8 +48,8 @@ describe('CBOR Typed Array Tagger', function() {
4848
});
4949

5050
it('should convert tagged Int8Array', function() {
51-
var data = hexToBuffer('d8484301fe03');
52-
var msg = CBOR.decode(data, cborTypedArrayTagger);
51+
const data = hexToBuffer('d8484301fe03');
52+
const msg = CBOR.decode(data, cborTypedArrayTagger);
5353

5454
expect(msg).to.be.a('Int8Array');
5555
expect(msg).to.have.lengthOf(3);
@@ -59,8 +59,8 @@ describe('CBOR Typed Array Tagger', function() {
5959
});
6060

6161
it('should convert tagged Int16Array', function() {
62-
var data = hexToBuffer('d84d460100feff0300');
63-
var msg = CBOR.decode(data, cborTypedArrayTagger);
62+
const data = hexToBuffer('d84d460100feff0300');
63+
const msg = CBOR.decode(data, cborTypedArrayTagger);
6464

6565
expect(msg).to.be.a('Int16Array');
6666
expect(msg).to.have.lengthOf(3);
@@ -70,8 +70,8 @@ describe('CBOR Typed Array Tagger', function() {
7070
});
7171

7272
it('should convert tagged Int32Array', function() {
73-
var data = hexToBuffer('d84e4c01000000feffffff03000000');
74-
var msg = CBOR.decode(data, cborTypedArrayTagger);
73+
const data = hexToBuffer('d84e4c01000000feffffff03000000');
74+
const msg = CBOR.decode(data, cborTypedArrayTagger);
7575

7676
expect(msg).to.be.a('Int32Array');
7777
expect(msg).to.have.lengthOf(3);
@@ -81,8 +81,8 @@ describe('CBOR Typed Array Tagger', function() {
8181
});
8282

8383
it('should convert tagged Int64Array', function() {
84-
var data = hexToBuffer('d84f58180100000000000000feffffffffffffff0300000000000000');
85-
var msg = CBOR.decode(data, cborTypedArrayTagger);
84+
const data = hexToBuffer('d84f58180100000000000000feffffffffffffff0300000000000000');
85+
const msg = CBOR.decode(data, cborTypedArrayTagger);
8686

8787
expect(msg).to.be.a('Array');
8888
expect(msg).to.have.lengthOf(3);
@@ -92,8 +92,8 @@ describe('CBOR Typed Array Tagger', function() {
9292
});
9393

9494
it('should convert tagged Float32Array', function() {
95-
var data = hexToBuffer('d8554ccdcc8c3fcdcc0cc033335340');
96-
var msg = CBOR.decode(data, cborTypedArrayTagger);
95+
const data = hexToBuffer('d8554ccdcc8c3fcdcc0cc033335340');
96+
const msg = CBOR.decode(data, cborTypedArrayTagger);
9797

9898
expect(msg).to.be.a('Float32Array');
9999
expect(msg).to.have.lengthOf(3);
@@ -103,8 +103,8 @@ describe('CBOR Typed Array Tagger', function() {
103103
});
104104

105105
it('should convert tagged Float64Array', function() {
106-
var data = hexToBuffer('d85658189a9999999999f13f9a999999999901c06666666666660a40');
107-
var msg = CBOR.decode(data, cborTypedArrayTagger);
106+
const data = hexToBuffer('d85658189a9999999999f13f9a999999999901c06666666666660a40');
107+
const msg = CBOR.decode(data, cborTypedArrayTagger);
108108

109109
expect(msg).to.be.a('Float64Array');
110110
expect(msg).to.have.lengthOf(3);
@@ -114,8 +114,8 @@ describe('CBOR Typed Array Tagger', function() {
114114
});
115115

116116
it('should be able to unpack two typed arrays', function() {
117-
var data = hexToBuffer('82d8484308fe05d84d460100feff0300');
118-
var msg = CBOR.decode(data, cborTypedArrayTagger);
117+
const data = hexToBuffer('82d8484308fe05d84d460100feff0300');
118+
const msg = CBOR.decode(data, cborTypedArrayTagger);
119119

120120
expect(msg).to.be.a('Array');
121121
expect(msg).to.have.lengthOf(2);

0 commit comments

Comments
 (0)