import type { AnySchema, ArraySchema, BitsetSchema, CodecSchema, EnumSchema, ObjectSchema, OptionalSchema, PrimitiveSchema, RefSchema, TupleSchema, TypedArraySchema, UnionSchema, } from './descriptors.ts'; import type { Reader, Writer } from './io.ts'; type Prim = { readonly kind: K; readonly __t?: T }; function p(kind: K): Prim { return Object.freeze({ kind }) as Prim; } export const s = Object.freeze({ u8: p<'u8', number>('u8') as PrimitiveSchema<'u8', number>, u16: p<'u16', number>('u16') as PrimitiveSchema<'u16', number>, u32: p<'u32', number>('u32') as PrimitiveSchema<'u32', number>, i8: p<'i8', number>('i8') as PrimitiveSchema<'i8', number>, i16: p<'i16', number>('i16') as PrimitiveSchema<'i16', number>, i32: p<'i32', number>('i32') as PrimitiveSchema<'i32', number>, u53: p<'u53', number>('u53') as PrimitiveSchema<'u53', number>, i53: p<'i53', number>('i53') as PrimitiveSchema<'i53', number>, u64: p<'u64', bigint>('u64') as PrimitiveSchema<'u64', bigint>, i64: p<'i64', bigint>('i64') as PrimitiveSchema<'i64', bigint>, f32: p<'f32', number>('f32') as PrimitiveSchema<'f32', number>, f64: p<'f64', number>('f64') as PrimitiveSchema<'f64', number>, bool: p<'bool', boolean>('bool') as PrimitiveSchema<'bool', boolean>, str: p<'str', string>('str') as PrimitiveSchema<'str', string>, bytes: p<'bytes', Uint8Array>('bytes') as PrimitiveSchema<'bytes', Uint8Array>, f32Array: p<'f32Array', Float32Array>('f32Array') as TypedArraySchema<'f32Array', Float32Array>, f64Array: p<'f64Array', Float64Array>('f64Array') as TypedArraySchema<'f64Array', Float64Array>, u8Array: p<'u8Array', Uint8Array>('u8Array') as TypedArraySchema<'u8Array', Uint8Array>, u16Array: p<'u16Array', Uint16Array>('u16Array') as TypedArraySchema<'u16Array', Uint16Array>, u32Array: p<'u32Array', Uint32Array>('u32Array') as TypedArraySchema<'u32Array', Uint32Array>, i32Array: p<'i32Array', Int32Array>('i32Array') as TypedArraySchema<'i32Array', Int32Array>, array(elem: E): ArraySchema { return { kind: 'array', elem }; }, optional(elem: E): OptionalSchema { return { kind: 'optional', elem }; }, enum(values: L): EnumSchema { if (values.length === 0) throw new Error('enum requires at least one value'); if (values.length > 256) throw new Error('enum supports up to 256 values'); return { kind: 'enum', values }; }, bitset(flags: L): BitsetSchema { if (flags.length === 0) throw new Error('bitset requires at least one flag'); if (flags.length > 64) throw new Error('bitset supports up to 64 flags'); return { kind: 'bitset', flags }; }, tuple(...elems: E): TupleSchema { return { kind: 'tuple', elems }; }, union>>( name: string, discriminator: D, variants: V, ): UnionSchema }> { const variantSchemas = {} as Record; let i = 0; for (const k of Object.keys(variants)) { variantSchemas[k] = { kind: 'object', name: `${name}::${k}`, fields: variants[k]!, }; i++; if (i > 256) throw new Error('union supports up to 256 variants'); } return { kind: 'union', name, discriminator, variants: variantSchemas as { [K in keyof V]: ObjectSchema }, }; }, ref(thunk: () => S): RefSchema { return { kind: 'ref', thunk }; }, codec(impl: { encode: (w: Writer, v: T) => void; decode: (r: Reader) => T }): CodecSchema { return { kind: 'codec', encode: impl.encode, decode: impl.decode }; }, }); export type SchemaBuilder = typeof s; export function defineSchema>( name: string, build: (s: SchemaBuilder) => F, ): ObjectSchema { return { kind: 'object', name, fields: build(s) }; }