diff --git a/member/i8a.test.ts b/member/i8a.test.ts index 6f3c71e..fd89d01 100644 --- a/member/i8a.test.ts +++ b/member/i8a.test.ts @@ -7,7 +7,7 @@ import { import { byteLength, byteOffset, getType, littleEndian } from '../macro.ts'; import { Struct } from '../struct.ts'; -import { memberI8A, memberU8A } from './i8a.ts'; +import { memberI8A, memberU8A, memberU8AC } from './i8a.ts'; Deno.test('memberI8A', () => { class Test extends Struct { @@ -130,3 +130,64 @@ Deno.test('memberU8A', () => { assertEquals(test.alpha, source); assertNotStrictEquals(test.alpha, source); }); + +Deno.test('memberU8AC', () => { + class Test extends Struct { + declare public readonly ['constructor']: typeof Test; + + declare public alpha: Uint8ClampedArray; + + declare public beta: Uint8ClampedArray; + + declare public gamma: Uint8ClampedArray; + + public static override readonly BYTE_LENGTH: number = ((o) => { + o += memberU8AC(2, this, 'alpha', o); + o += memberU8AC(4, this, 'beta', o); + o += memberU8AC(0, this, 'gamma', o); + return o; + })(super.BYTE_LENGTH); + } + + const off = { + alpha: byteOffset(Test, 'alpha'), + beta: byteOffset(Test, 'beta'), + gamma: byteOffset(Test, 'gamma'), + }; + + assertEquals(Test.BYTE_LENGTH, 6); + assertEquals(byteLength(Test, 'alpha'), 2); + assertEquals(byteLength(Test, 'beta'), 4); + assertEquals(byteLength(Test, 'gamma'), 0); + assertEquals(littleEndian(Test, 'alpha'), null); + assertEquals(littleEndian(Test, 'beta'), null); + assertEquals(littleEndian(Test, 'gamma'), null); + assertEquals(getType(Test, 'alpha'), Uint8ClampedArray); + assertEquals(getType(Test, 'beta'), Uint8ClampedArray); + assertEquals(getType(Test, 'gamma'), Uint8ClampedArray); + + const data = new Uint8Array(Test.BYTE_LENGTH); + const test = new Test(data.buffer); + test.alpha[0] = 1; + test.alpha[1] = 0xff + 1; + test.beta[0] = 2; + test.beta[1] = 0xfe; + test.beta[2] = 3; + test.beta[3] = 0xfd; + + assertEquals(test.byteLength, Test.BYTE_LENGTH); + assertEquals(test.gamma.length, 0); + assertEquals(data[off.alpha], 1); + assertEquals(data[off.alpha + 1], 0xff); + assertEquals(data[off.beta], 2); + assertEquals(data[off.beta + 1], 0xfe); + assertEquals(data[off.beta + 2], 3); + assertEquals(data[off.beta + 3], 0xfd); + + assertStrictEquals(test.alpha, test.alpha); + + const source = new Uint8ClampedArray([4, 252]); + test.alpha = source; + assertEquals(test.alpha, source); + assertNotStrictEquals(test.alpha, source); +}); diff --git a/member/i8a.ts b/member/i8a.ts index 704cc49..e67a6a8 100644 --- a/member/i8a.ts +++ b/member/i8a.ts @@ -73,3 +73,38 @@ export function memberU8A( }, ); } + +/** + * Member uint8 array clamped. + * + * @param count Array length. + * @param StructC Struct constructor. + * @param name Member name. + * @param byteOffset Byte offset. + * @returns Byte length. + */ +export function memberU8AC( + count: number, + StructC: C, + name: MembersExtends, + byteOffset: number, +): number { + return memberView( + StructC, + name, + byteOffset, + count, + null, + Uint8ClampedArray, + function (): Uint8ClampedArray { + return new Uint8ClampedArray( + this.buffer, + this.byteOffset + byteOffset, + count, + ); + }, + function (value: Uint8ClampedArray): void { + assignView(this[name] as Uint8ClampedArray, value); + }, + ); +} diff --git a/type.ts b/type.ts index 1f4fe87..c0ab594 100644 --- a/type.ts +++ b/type.ts @@ -28,7 +28,11 @@ export type ArrayBufferReal = ArrayBufferLike & { BYTES_PER_ELEMENT?: never }; /** * Types of child structures. */ -export type ChildTypes = typeof Int8Array | typeof Uint8Array | typeof Struct; +export type ChildTypes = + | typeof Int8Array + | typeof Uint8Array + | typeof Uint8ClampedArray + | typeof Struct; /** * Types of member type.