Fix parameter ordering and defaults

This commit is contained in:
Tony Garnock-Jones 2021-01-29 15:35:07 +01:00
parent 013c5f4dae
commit 1743756097
4 changed files with 37 additions and 35 deletions

View File

@ -1,6 +1,6 @@
{
"name": "preserves",
"version": "0.5.0",
"version": "0.5.1",
"description": "Experimental data serialization format",
"homepage": "https://gitlab.com/preserves/preserves",
"license": "Apache-2.0",

View File

@ -135,8 +135,8 @@ export class Decoder<T extends object> {
return this.includeAnnotations ? new Annotated(v) : v;
}
static dictionaryFromArray<T extends object>(vs: Value<T>[]): Dictionary<T, Value<T>> {
const d = new Dictionary<T, Value<T>>();
static dictionaryFromArray<T extends object>(vs: Value<T>[]): Dictionary<Value<T>, T> {
const d = new Dictionary<Value<T>, T>();
if (vs.length % 2) throw new DecodeError("Missing dictionary value");
for (let i = 0; i < vs.length; i += 2) {
d.set(vs[i], vs[i+1]);

View File

@ -9,15 +9,17 @@ import { _iterMap, FlexMap, FlexSet } from './flex';
const textEncoder = new TextEncoder();
const textDecoder = new TextDecoder();
export type Value<T extends object> = Atom | Compound<T> | T | Annotated<T>;
export type DefaultPointer = object
export type Value<T extends object = DefaultPointer> = Atom | Compound<T> | T | Annotated<T>;
export type Atom = boolean | Single | Double | number | string | Bytes | symbol;
export type Compound<T extends object> = Record<T> | Array<Value<T>> | Set<T> | Dictionary<T, Value<T>>;
export type Compound<T extends object = DefaultPointer> = Record<T> | Array<Value<T>> | Set<T> | Dictionary<Value<T>, T>;
export const IsPreservesRecord = Symbol.for('IsPreservesRecord');
export const IsPreservesBytes = Symbol.for('IsPreservesBytes');
export const IsPreservesAnnotated = Symbol.for('IsPreservesAnnotated');
export function fromJS<T extends object>(x: any): Value<T> {
export function fromJS<T extends object = DefaultPointer>(x: any): Value<T> {
switch (typeof x) {
case 'number':
if (!Number.isInteger(x)) {
@ -95,7 +97,7 @@ export abstract class Float {
}
export class Single extends Float implements Preservable<never> {
[AsPreserve]<T extends object>(): Value<T> {
[AsPreserve]<T extends object = DefaultPointer>(): Value<T> {
return this;
}
@ -116,7 +118,7 @@ export class Single extends Float implements Preservable<never> {
}
export class Double extends Float implements Preservable<never> {
[AsPreserve]<T extends object>(): Value<T> {
[AsPreserve]<T extends object = DefaultPointer>(): Value<T> {
return this;
}
@ -254,7 +256,7 @@ export class Bytes implements Preservable<never> {
return this.asPreservesText();
}
[AsPreserve]<T extends object>(): Value<T> {
[AsPreserve]<T extends object = DefaultPointer>(): Value<T> {
return this;
}
@ -416,7 +418,7 @@ keys lastIndexOf reduce reduceRight some toLocaleString values`.split(/\s+/))
Bytes.prototype[Symbol.iterator] = function () { return this._view[Symbol.iterator](); };
})();
export class Record<T extends object> extends Array<Value<T>> {
export class Record<T extends object = DefaultPointer> extends Array<Value<T>> {
readonly label: Value<T>;
constructor(label: Value<T>, fieldsJS: any[]) {
@ -482,11 +484,11 @@ export class Record<T extends object> extends Array<Value<T>> {
}).join(', ') + ')';
}
static makeConstructor<T extends object>(labelSymbolText: string, fieldNames: string[]): RecordConstructor<T> {
static makeConstructor<T extends object = DefaultPointer>(labelSymbolText: string, fieldNames: string[]): RecordConstructor<T> {
return Record.makeBasicConstructor(Symbol.for(labelSymbolText), fieldNames);
}
static makeBasicConstructor<T extends object>(label0: any, fieldNames: string[]): RecordConstructor<T> {
static makeBasicConstructor<T extends object = DefaultPointer>(label0: any, fieldNames: string[]): RecordConstructor<T> {
const label = fromJS<T>(label0);
const arity = fieldNames.length;
const ctor: RecordConstructor<T> = (...fields: any[]): Record<T> => {
@ -523,23 +525,23 @@ export class Record<T extends object> extends Array<Value<T>> {
return true;
}
static isRecord<T extends object>(x: any): x is Record<T> {
static isRecord<T extends object = DefaultPointer>(x: any): x is Record<T> {
return !!x?.[IsPreservesRecord];
}
static isClassOf<T extends object>(ci: RecordConstructorInfo<T>, v: any): v is Record<T> {
static isClassOf<T extends object = DefaultPointer>(ci: RecordConstructorInfo<T>, v: any): v is Record<T> {
return (Record.isRecord(v)) && is(ci.label, v.label) && (ci.arity === v.length);
}
}
export interface RecordConstructor<T extends object> {
export interface RecordConstructor<T extends object = DefaultPointer> {
(...fields: any[]): Record<T>;
constructorInfo: RecordConstructorInfo<T>;
isClassOf(v: any): v is Record<T>;
_: { [getter: string]: (r: any) => Value<T> | undefined };
}
export interface RecordConstructorInfo<T extends object> {
export interface RecordConstructorInfo<T extends object = DefaultPointer> {
label: Value<T>;
arity: number;
}
@ -564,18 +566,18 @@ export function is(a: any, b: any): boolean {
export type DictionaryType = 'Dictionary' | 'Set';
export const DictionaryType = Symbol.for('DictionaryType');
export class Dictionary<T extends object, V> extends FlexMap<Value<T>, V> {
export class Dictionary<V, T extends object = DefaultPointer> extends FlexMap<Value<T>, V> {
get [DictionaryType](): DictionaryType {
return 'Dictionary';
}
static isDictionary<T extends object, V>(x: any): x is Dictionary<T, V> {
static isDictionary<V, T extends object = DefaultPointer>(x: any): x is Dictionary<V, T> {
return x?.[DictionaryType] === 'Dictionary';
}
static fromJS<T extends object, V extends object>(x: object): Dictionary<T, Value<V>> {
if (Dictionary.isDictionary<T, V>(x)) return x as Dictionary<T, Value<V>>;
const d = new Dictionary<T, Value<V>>();
static fromJS<V extends object = DefaultPointer, T extends object = DefaultPointer>(x: object): Dictionary<Value<V>, T> {
if (Dictionary.isDictionary<V, T>(x)) return x as Dictionary<Value<V>, T>;
const d = new Dictionary<Value<V>, T>();
Object.entries(x).forEach(([key, value]) => d.set(key, fromJS(value)));
return d;
}
@ -585,8 +587,8 @@ export class Dictionary<T extends object, V> extends FlexMap<Value<T>, V> {
super(canonicalString, iter === void 0 ? void 0 : _iterMap(iter, ([k,v]) => [fromJS(k), v]));
}
mapEntries<R extends object, W>(f: (entry: [Value<T>, V]) => [Value<R>, W]): Dictionary<R, W> {
const result = new Dictionary<R, W>();
mapEntries<W, R extends object = DefaultPointer>(f: (entry: [Value<T>, V]) => [Value<R>, W]): Dictionary<W, R> {
const result = new Dictionary<W, R>();
for (let oldEntry of this.entries()) {
const newEntry = f(oldEntry);
result.set(newEntry[0], newEntry[1])
@ -601,7 +603,7 @@ export class Dictionary<T extends object, V> extends FlexMap<Value<T>, V> {
'}';
}
clone(): Dictionary<T, V> {
clone(): Dictionary<V, T> {
return new Dictionary(this);
}
@ -628,12 +630,12 @@ export class Dictionary<T extends object, V> extends FlexMap<Value<T>, V> {
}
}
export class Set<T extends object> extends FlexSet<Value<T>> {
export class Set<T extends object = DefaultPointer> extends FlexSet<Value<T>> {
get [DictionaryType](): DictionaryType {
return 'Set';
}
static isSet<T extends object>(x: any): x is Set<T> {
static isSet<T extends object = DefaultPointer>(x: any): x is Set<T> {
return x?.[DictionaryType] === 'Set';
}
@ -642,7 +644,7 @@ export class Set<T extends object> extends FlexSet<Value<T>> {
super(canonicalString, iter === void 0 ? void 0 : _iterMap<any, Value<T>>(iter, fromJS));
}
map<R extends object>(f: (value: Value<T>) => Value<R>): Set<R> {
map<R extends object = DefaultPointer>(f: (value: Value<T>) => Value<R>): Set<R> {
return new Set(_iterMap(this[Symbol.iterator](), f));
}
@ -679,7 +681,7 @@ export class Set<T extends object> extends FlexSet<Value<T>> {
}
}
export class Annotated<T extends object> {
export class Annotated<T extends object = DefaultPointer> {
readonly annotations: Array<Value<T>>;
readonly item: Value<T>;
@ -723,16 +725,16 @@ export class Annotated<T extends object> {
return true;
}
static isAnnotated<T extends object>(x: any): x is Annotated<T> {
static isAnnotated<T extends object = DefaultPointer>(x: any): x is Annotated<T> {
return !!x?.[IsPreservesAnnotated];
}
}
export function peel<T extends object>(v: Value<T>): Value<T> {
export function peel<T extends object = DefaultPointer>(v: Value<T>): Value<T> {
return strip(v, 1);
}
export function strip<T extends object>(v: Value<T>, depth: number = Infinity): Value<T> {
export function strip<T extends object = DefaultPointer>(v: Value<T>, depth: number = Infinity): Value<T> {
function step(v: Value<T>, depth: number): Value<T> {
if (depth === 0) return v;
if (!Annotated.isAnnotated<T>(v)) return v;
@ -746,7 +748,7 @@ export function strip<T extends object>(v: Value<T>, depth: number = Infinity):
return v.item.map(walk);
} else if (Set.isSet<T>(v.item)) {
return v.item.map(walk);
} else if (Dictionary.isDictionary<T, Value<T>>(v.item)) {
} else if (Dictionary.isDictionary<Value<T>, T>(v.item)) {
return v.item.mapEntries((e) => [walk(e[0]), walk(e[1])]);
} else if (Annotated.isAnnotated(v.item)) {
throw new Error("Improper annotation structure");
@ -757,7 +759,7 @@ export function strip<T extends object>(v: Value<T>, depth: number = Infinity):
return step(v, depth);
}
export function annotate<T extends object>(v0: Value<T>, ...anns: Value<T>[]): Annotated<T> {
export function annotate<T extends object = DefaultPointer>(v0: Value<T>, ...anns: Value<T>[]): Annotated<T> {
const v = Annotated.isAnnotated<T>(v0) ? v0 : new Annotated(v0);
anns.forEach((a) => v.annotations.push(a));
return v;

View File

@ -151,7 +151,7 @@ describe('encoding and decoding pointers', () => {
it('should store pointers embedded in map keys correctly', () => {
const A1 = ({a: 1});
const A2 = ({a: 1});
const m = new Dictionary<object, Value<object>>();
const m = new Dictionary();
m.set([A1], 1);
m.set([A2], 2);
expect(m.get(A1)).toBeUndefined();
@ -241,7 +241,7 @@ describe('common test suite', () => {
});
}
const tests = peel(TestCases._.cases(peel(samples))!) as Dictionary<Pointer, Value<Pointer>>;
const tests = peel(TestCases._.cases(peel(samples))!) as Dictionary<Value<Pointer>, Pointer>;
tests.forEach((t0: Value<Pointer>, tName0: Value<Pointer>) => {
const tName = Symbol.keyFor(strip(tName0) as symbol)!;
const t = peel(t0) as Record<Pointer>;