Skip to content

Commit

Permalink
Support data alignment in the custom extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
EddiG committed Aug 23, 2024
1 parent 12046e7 commit 2796aef
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 3 deletions.
12 changes: 10 additions & 2 deletions src/Decoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -687,8 +687,16 @@ export class Decoder<ContextType = undefined> {
throw new DecodeError(`Max length exceeded: ext length (${size}) > maxExtLength (${this.maxExtLength})`);
}

const extType = this.view.getInt8(this.pos + headOffset);
const data = this.decodeBinary(size, headOffset + 1 /* extType */);
let padding = 0;
let extType = this.view.getInt8(this.pos + headOffset);

// 0xc1 => -63 (Int8) (noop byte)
while (extType === -63) {
padding++;
extType = this.view.getInt8(this.pos + headOffset + padding);
}

const data = this.decodeBinary(size, headOffset + padding + 1 /* extType */);
return this.extensionCodec.decode(data, extType, this.context);
}

Expand Down
8 changes: 8 additions & 0 deletions src/Encoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,14 @@ export class Encoder<ContextType = undefined> {
} else {
throw new Error(`Too large extension object: ${size}`);
}
if (ext.align && Number.isInteger(ext.align)) {
const align = ext.align;
const dataPos = this.pos + 1; // + extType size
const padding = (align - (dataPos % align)) % align;
for (let i = 0; i < padding; i++) {
this.writeU8(0xc1); // noop byte
}
}
this.writeI8(ext.type);
this.writeU8a(ext.data);
}
Expand Down
1 change: 1 addition & 0 deletions src/ExtData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ export class ExtData {
constructor(
readonly type: number,
readonly data: Uint8Array,
readonly align: number | undefined | null = null,
) {}
}
7 changes: 6 additions & 1 deletion src/ExtensionCodec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,28 @@ export class ExtensionCodec<ContextType = undefined> implements ExtensionCodecTy
// custom extensions
private readonly encoders: Array<ExtensionEncoderType<ContextType> | undefined | null> = [];
private readonly decoders: Array<ExtensionDecoderType<ContextType> | undefined | null> = [];
private readonly aligns: Array<number | undefined | null> = [];

public constructor() {
this.register(timestampExtension);
}

public register({
type,
align,
encode,
decode,
}: {
type: number;
align?: number;
encode: ExtensionEncoderType<ContextType>;
decode: ExtensionDecoderType<ContextType>;
}): void {
if (type >= 0) {
// custom extensions
this.encoders[type] = encode;
this.decoders[type] = decode;
this.aligns[type] = align;
} else {
// built-in extensions
const index = 1 + type;
Expand Down Expand Up @@ -80,7 +84,8 @@ export class ExtensionCodec<ContextType = undefined> implements ExtensionCodecTy
const data = encodeExt(object, context);
if (data != null) {
const type = i;
return new ExtData(type, data);
const align = this.aligns[type];
return new ExtData(type, data, align);
}
}
}
Expand Down
28 changes: 28 additions & 0 deletions test/ExtensionCodec.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,4 +196,32 @@ describe("ExtensionCodec", () => {
]);
});
});

context("custom extensions with alignment", () => {
const extensionCodec = new ExtensionCodec();

extensionCodec.register({
type: 0x01,
align: 4,
encode: (object: unknown): Uint8Array | null => {
if (object instanceof Float32Array) {
return new Uint8Array(object.buffer);
}
return null;
},
decode: (data: Uint8Array) => {
return new Float32Array(data.buffer, data.byteOffset, data.byteLength / Float32Array.BYTES_PER_ELEMENT);
},
});

it("encodes and decodes Float32Array type with zero-copy", () => {
const data = {
position: new Float32Array([1.1, 2.2, 3.3, 4.4, 5.5]),
};
const encoded = encode(data, { extensionCodec });
const decoded = decode(encoded, { extensionCodec });
assert.deepStrictEqual(decoded, data);
assert.strictEqual(decoded.position.buffer, encoded.buffer);
});
});
});

0 comments on commit 2796aef

Please sign in to comment.