Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2796aef

Browse files
committed
Support data alignment in the custom extensions
1 parent 12046e7 commit 2796aef

File tree

5 files changed

+53
-3
lines changed

5 files changed

+53
-3
lines changed

‎src/Decoder.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -687,8 +687,16 @@ export class Decoder<ContextType = undefined> {
687687
throw new DecodeError(`Max length exceeded: ext length (${size}) > maxExtLength (${this.maxExtLength})`);
688688
}
689689

690-
const extType = this.view.getInt8(this.pos + headOffset);
691-
const data = this.decodeBinary(size, headOffset + 1 /* extType */);
690+
let padding = 0;
691+
let extType = this.view.getInt8(this.pos + headOffset);
692+
693+
// 0xc1 => -63 (Int8) (noop byte)
694+
while (extType === -63) {
695+
padding++;
696+
extType = this.view.getInt8(this.pos + headOffset + padding);
697+
}
698+
699+
const data = this.decodeBinary(size, headOffset + padding + 1 /* extType */);
692700
return this.extensionCodec.decode(data, extType, this.context);
693701
}
694702

‎src/Encoder.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,14 @@ export class Encoder<ContextType = undefined> {
427427
} else {
428428
throw new Error(`Too large extension object: ${size}`);
429429
}
430+
if (ext.align && Number.isInteger(ext.align)) {
431+
const align = ext.align;
432+
const dataPos = this.pos + 1; // + extType size
433+
const padding = (align - (dataPos % align)) % align;
434+
for (let i = 0; i < padding; i++) {
435+
this.writeU8(0xc1); // noop byte
436+
}
437+
}
430438
this.writeI8(ext.type);
431439
this.writeU8a(ext.data);
432440
}

‎src/ExtData.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ export class ExtData {
55
constructor(
66
readonly type: number,
77
readonly data: Uint8Array,
8+
readonly align: number | undefined | null = null,
89
) {}
910
}

‎src/ExtensionCodec.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,24 +34,28 @@ export class ExtensionCodec<ContextType = undefined> implements ExtensionCodecTy
3434
// custom extensions
3535
private readonly encoders: Array<ExtensionEncoderType<ContextType> | undefined | null> = [];
3636
private readonly decoders: Array<ExtensionDecoderType<ContextType> | undefined | null> = [];
37+
private readonly aligns: Array<number | undefined | null> = [];
3738

3839
public constructor() {
3940
this.register(timestampExtension);
4041
}
4142

4243
public register({
4344
type,
45+
align,
4446
encode,
4547
decode,
4648
}: {
4749
type: number;
50+
align?: number;
4851
encode: ExtensionEncoderType<ContextType>;
4952
decode: ExtensionDecoderType<ContextType>;
5053
}): void {
5154
if (type >= 0) {
5255
// custom extensions
5356
this.encoders[type] = encode;
5457
this.decoders[type] = decode;
58+
this.aligns[type] = align;
5559
} else {
5660
// built-in extensions
5761
const index = 1 + type;
@@ -80,7 +84,8 @@ export class ExtensionCodec<ContextType = undefined> implements ExtensionCodecTy
8084
const data = encodeExt(object, context);
8185
if (data != null) {
8286
const type = i;
83-
return new ExtData(type, data);
87+
const align = this.aligns[type];
88+
return new ExtData(type, data, align);
8489
}
8590
}
8691
}

‎test/ExtensionCodec.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,4 +196,32 @@ describe("ExtensionCodec", () => {
196196
]);
197197
});
198198
});
199+
200+
context("custom extensions with alignment", () => {
201+
const extensionCodec = new ExtensionCodec();
202+
203+
extensionCodec.register({
204+
type: 0x01,
205+
align: 4,
206+
encode: (object: unknown): Uint8Array | null => {
207+
if (object instanceof Float32Array) {
208+
return new Uint8Array(object.buffer);
209+
}
210+
return null;
211+
},
212+
decode: (data: Uint8Array) => {
213+
return new Float32Array(data.buffer, data.byteOffset, data.byteLength / Float32Array.BYTES_PER_ELEMENT);
214+
},
215+
});
216+
217+
it("encodes and decodes Float32Array type with zero-copy", () => {
218+
const data = {
219+
position: new Float32Array([1.1, 2.2, 3.3, 4.4, 5.5]),
220+
};
221+
const encoded = encode(data, { extensionCodec });
222+
const decoded = decode(encoded, { extensionCodec });
223+
assert.deepStrictEqual(decoded, data);
224+
assert.strictEqual(decoded.position.buffer, encoded.buffer);
225+
});
226+
});
199227
});

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /