import { Record, Tuple } from "./record"; import { Bytes } from "./bytes"; import { fold } from "./fold"; import { is } from "./is"; import { Value } from "./values"; import { Set, Dictionary } from "./dictionary"; import { Annotated } from "./annotated"; import { unannotate } from "./strip"; import { embed, isEmbedded, Embedded } from "./embedded"; export function merge( mergeEmbeddeds: (a: T, b: T) => T | undefined, item0: Value, ... items: Array>): Value { function die(): never { throw new Error("Cannot merge items"); } function walk(a: Value, b: Value): Value { if (a === b) return a; return fold>(a, { boolean: die, single(_f: number) { return is(a, b) ? a : die(); }, double(_f: number) { return is(a, b) ? a : die(); }, integer: die, string: die, bytes(_b: Bytes) { return is(a, b) ? a : die(); }, symbol: die, record(r: Record, Tuple>, T>) { if (!Record.isRecord, Tuple>, T>(b)) die(); return Record(walk(r.label, b.label), walkMany(r, b)); }, array(a: Array>) { if (!Array.isArray(b) || Record.isRecord(b)) die(); return walkMany(a, b); }, set(_s: Set) { die(); }, dictionary(d: Dictionary) { if (!Dictionary.isDictionary(b)) die(); const r = new Dictionary(); d.forEach((av,ak) => { const bv = b.get(ak); r.set(ak, bv === void 0 ? av : walk(av, bv)); }); b.forEach((bv, bk) => { if (!d.has(bk)) r.set(bk, bv); }); return r; }, annotated(a: Annotated) { return walk(a, unannotate(b)); }, embedded(t: Embedded) { if (!isEmbedded(b)) die(); const r = mergeEmbeddeds(t.embeddedValue, b.embeddedValue); if (r === void 0) die(); return embed(r); }, }); } function walkMany(a: Array>, b: Array>): Array> { if (a.length !== b.length) die(); return a.map((aa, i) => walk(aa, b[i])); } return items.reduce(walk, item0); }