Skip to content

Unions ​

A union places every member at offset 0, so the members overlap and the union's size equals the widest member. Unions are used for type punning and tagged variants.

Fixed-size members only

A union does not support dynamic strings. Length-prefixed, null-terminated, and bare 'utf8' / 'ascii' / 'string' members are rejected at construction, because writing them resizes the buffer and would corrupt every overlapping member. Use a fixed-size string instead, such as 'utf8(N)' or { type: 'utf8', size: N }.

Basics ​

ts
import { Union } from '@remotex-labs/xstruct';

const value = new Union<{ int: number; float: number }>({
    int: 'UInt32LE',
    float: 'FloatLE'
});

value.size; // 4, the widest member

Union extends Struct, so it shares the size, toBuffer, and toObject API and can be nested inside any struct schema.

Write semantics ​

Only the first member with a defined value is written; declaration order sets the priority. The rest of the buffer is zero-filled.

ts
const buffer = value.toBuffer({ float: 5.0 }); 

Provide exactly one member per toBuffer call, and list members in priority order so the intended one wins.

Read semantics ​

Every member is decoded from the same bytes, which is the type punning a union provides.

ts
const decoded = value.toObject(buffer);
decoded.float; // 5.0
decoded.int;   // 1084227584, the same bytes read as a UInt32LE

Tagged variants ​

Pair a union with a discriminator field in an enclosing struct, and read the tag first.

ts
import { Struct, Union } from '@remotex-labs/xstruct';

const Packet = new Struct<{ kind: number; payload: { int: number; float: number } }>({
    kind: 'UInt8',
    payload: new Union({ int: 'UInt32LE', float: 'FloatLE' }) 
});

Allowed members ​

MemberAllowed
Primitive, array, bitfieldYes
Nested struct or unionYes
Fixed-size string, { size: N } or utf8(N)Yes
Length-prefixed, null-terminated, or bare stringNo

Dynamic strings are rejected when the union is constructed:

ts
new Union({ name: 'utf8' });                     
new Union({ name: 'utf8(16)' });                 // ok, fixed size
new Union({ name: { type: 'utf8', size: 16 } }); // ok, fixed size
Why dynamic strings are not allowed

A length-prefixed or null-terminated string has a size that depends on its content. Writing one would grow the buffer past the union's fixed size and overwrite the bytes shared with every other member. Fixed-size strings have a constant width, so they overlap safely.

See also ​