Skip to content

Commit

Permalink
add "untagged" union.
Browse files Browse the repository at this point in the history
  • Loading branch information
MierenManz committed Jun 13, 2024
1 parent 2f5949a commit 102acc4
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/compound/tagged_union.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type FindDiscriminant<V, D extends number | string> = (variant: V) => D;

type Keys<T> = Exclude<keyof T, symbol>;

/** Union for when the inner type's don't write their own discriminant */
export class TaggedUnion<
T extends Record<string | number, UnsizedType<unknown>>,
V extends ValueOf<{ [K in keyof T]: InnerType<T[K]> }> = ValueOf<
Expand Down
60 changes: 60 additions & 0 deletions src/compound/union.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { u8 } from "../primitives/mod.ts";
import {
type InnerType,
type Options,
UnsizedType,
type ValueOf,
} from "../types/mod.ts";
import { getBiggestAlignment } from "../util.ts";

type FindDiscriminant<V, D extends number> = (variant: V) => D;

type Keys<T> = Exclude<keyof T, symbol | string>;

/** Union for when the inner type's do write their own discriminant */
export class Union<
T extends Record<number, UnsizedType<unknown>>,
V extends ValueOf<{ [K in keyof T]: InnerType<T[K]> }>,
> extends UnsizedType<V> {

#record: T;
#variantFinder: FindDiscriminant<V, Keys<T>>;
#discriminant = u8;

constructor(
input: T,
variantFinder: FindDiscriminant<V, Keys<T>>,
) {
super(getBiggestAlignment(input));
this.#record = input;
this.#variantFinder = variantFinder;
}

readPacked(dt: DataView, options: Options = { byteOffset: 0 }): V {
const discriminant = this.#discriminant.readPacked(dt, { byteOffset: options.byteOffset });
const codec = this.#record[discriminant];
if (!codec) throw new TypeError("Unknown discriminant");
return codec.readPacked(dt, options) as V;
}

read(dt: DataView, options: Options = { byteOffset: 0 }): V {
const discriminant = this.#discriminant.read(dt, { byteOffset: options.byteOffset });
const codec = this.#record[discriminant];
if (!codec) throw new TypeError("Unknown discriminant");
return codec.readPacked(dt, options) as V;
}

writePacked(variant: V, dt: DataView, options: Options = { byteOffset: 0 }): void {
const discriminant = this.#variantFinder(variant);
const codec = this.#record[discriminant];
if (!codec) throw new TypeError("Unknown discriminant");
codec.writePacked(variant, dt, options) as V;
}

write(variant: V, dt: DataView, options: Options = { byteOffset: 0 }): void {
const discriminant = this.#variantFinder(variant);
const codec = this.#record[discriminant];
if (!codec) throw new TypeError("Unknown discriminant");
codec.write(variant, dt, options) as V;
}
}

0 comments on commit 102acc4

Please sign in to comment.