import { Encoder, EncoderState } from "./encoder"; import { Decoder, DecoderState } from "./decoder"; import type { Value } from "./values"; import { strip } from "./strip"; export type PointerType = { decode(s: DecoderState): T; encode(s: EncoderState, v: T): void; fromValue(v: Value): T; toValue(v: T): Value; } export class Pointer { embeddedValue: T; constructor(embeddedValue: T) { this.embeddedValue = embeddedValue; } equals(other: any, is: (a: any, b: any) => boolean) { return isPointer(other) && is(this.embeddedValue, other.embeddedValue); } asPreservesText(): string { return '#!' + (this.embeddedValue as any).asPreservesText(); } } export function embed(embeddedValue: T): Pointer { return new Pointer(embeddedValue); } export function isPointer(v: Value): v is Pointer { return typeof v === 'object' && 'embeddedValue' in v; } export class GenericPointer { generic: Value; constructor(generic: Value) { this.generic = generic; } equals(other: any, is: (a: any, b: any) => boolean) { return typeof other === 'object' && 'generic' in other && is(this.generic, other.generic); } asPreservesText(): string { return this.generic.asPreservesText(); } } export const genericPointerType: PointerType = { decode(s: DecoderState): GenericPointer { return new GenericPointer(new Decoder(s, this).next()); }, encode(s: EncoderState, v: GenericPointer): void { new Encoder(s, this).push(v.generic); }, fromValue(v: Value): GenericPointer { return new GenericPointer(strip(v)); }, toValue(v: GenericPointer): Value { return v.generic; } }; export const neverPointerType: PointerType = { decode(_s: DecoderState): never { throw new Error("Pointers not permitted at this point in Preserves document"); }, encode(_s: EncoderState, _v: never): void { throw new Error("Pointers not permitted encoding Preserves document"); }, fromValue(_v: Value): never { throw new Error("Pointers not permitted at this point in Preserves document"); }, toValue(_v: never): Value { throw new Error("Pointers not permitted encoding Preserves document"); } }; let _nextId = 0; const _registry = new WeakMap(); export function pointerId(v: any): number { let id = _registry.get(v); if (id === void 0) { id = _nextId++; _registry.set(v, id); } return id; } export const identityPointerType: PointerType = { decode(_s: DecoderState): any { throw new Error("Cannot decode identityPointerType"); }, encode(s: EncoderState, v: any): void { new Encoder(s, this).push(pointerId(v)); }, fromValue(_v: Value): any { throw new Error("Cannot decode identityPointerType"); }, toValue(v: any): Value { return pointerId(v); } };