2021-04-22 18:51:48 +00:00
|
|
|
import { Encoder, EncoderState } from "./encoder";
|
2021-04-24 19:59:52 +00:00
|
|
|
import { Decoder, DecoderState } from "./decoder";
|
2021-03-17 09:21:48 +00:00
|
|
|
import type { Value } from "./values";
|
|
|
|
import { strip } from "./strip";
|
|
|
|
|
2021-04-24 19:59:52 +00:00
|
|
|
export type PointerType<T> = {
|
|
|
|
decode(s: DecoderState): T;
|
|
|
|
encode(s: EncoderState, v: T): void;
|
|
|
|
|
|
|
|
fromValue(v: Value<DefaultPointer>): T;
|
|
|
|
toValue(v: T): Value<DefaultPointer>;
|
|
|
|
}
|
2021-03-17 09:21:48 +00:00
|
|
|
|
2021-04-24 19:59:52 +00:00
|
|
|
export class Pointer<T> {
|
|
|
|
embeddedValue: T;
|
|
|
|
|
|
|
|
constructor(embeddedValue: T) {
|
|
|
|
this.embeddedValue = embeddedValue;
|
2021-03-17 09:21:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
equals(other: any, is: (a: any, b: any) => boolean) {
|
2021-04-24 19:59:52 +00:00
|
|
|
return isPointer<T>(other) && is(this.embeddedValue, other.embeddedValue);
|
2021-03-17 09:21:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
asPreservesText(): string {
|
2021-04-24 19:59:52 +00:00
|
|
|
return '#!' + (this.embeddedValue as any).asPreservesText();
|
2021-03-17 09:21:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-24 19:59:52 +00:00
|
|
|
export function embed<T>(embeddedValue: T): Pointer<T> {
|
|
|
|
return new Pointer(embeddedValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function isPointer<T>(v: Value<T>): v is Pointer<T> {
|
|
|
|
return typeof v === 'object' && 'embeddedValue' in v;
|
2021-03-17 09:21:48 +00:00
|
|
|
}
|
|
|
|
|
2021-04-24 19:59:52 +00:00
|
|
|
export class DefaultPointer {
|
|
|
|
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();
|
|
|
|
}
|
2021-03-17 09:21:48 +00:00
|
|
|
}
|
|
|
|
|
2021-04-24 19:59:52 +00:00
|
|
|
export const genericPointerType: PointerType<DefaultPointer> = {
|
|
|
|
decode(s: DecoderState): DefaultPointer {
|
|
|
|
return new DefaultPointer(new Decoder(s, this).next());
|
|
|
|
},
|
|
|
|
|
|
|
|
encode(s: EncoderState, v: DefaultPointer): void {
|
|
|
|
new Encoder(s, this).push(v.generic);
|
|
|
|
},
|
|
|
|
|
|
|
|
fromValue(v: Value<DefaultPointer>): DefaultPointer {
|
|
|
|
return new DefaultPointer(strip(v));
|
|
|
|
},
|
|
|
|
|
|
|
|
toValue(v: DefaultPointer): Value<DefaultPointer> {
|
|
|
|
return v.generic;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
export const neverPointerType: PointerType<never> = {
|
|
|
|
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<DefaultPointer>): never {
|
|
|
|
throw new Error("Pointers not permitted at this point in Preserves document");
|
|
|
|
},
|
|
|
|
|
|
|
|
toValue(_v: never): Value<DefaultPointer> {
|
|
|
|
throw new Error("Pointers not permitted encoding Preserves document");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let _nextId = 0;
|
|
|
|
const _registry = new WeakMap<object, number>();
|
|
|
|
export function pointerId(v: any): number {
|
|
|
|
let id = _registry.get(v);
|
|
|
|
if (id === void 0) {
|
|
|
|
id = _nextId++;
|
|
|
|
_registry.set(v, id);
|
|
|
|
}
|
|
|
|
return id;
|
2021-03-17 09:21:48 +00:00
|
|
|
}
|
2021-04-24 19:59:52 +00:00
|
|
|
|
|
|
|
export const identityPointerType: PointerType<any> = {
|
|
|
|
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<DefaultPointer>): any {
|
|
|
|
throw new Error("Cannot decode identityPointerType");
|
|
|
|
},
|
|
|
|
|
|
|
|
toValue(v: any): Value<DefaultPointer> {
|
|
|
|
return pointerId(v);
|
|
|
|
}
|
|
|
|
};
|