2021-03-23 10:36:11 +00:00
|
|
|
import { Record, Tuple } from "./record";
|
|
|
|
import { Bytes } from "./bytes";
|
2021-04-24 19:59:52 +00:00
|
|
|
import { fold } from "./fold";
|
2021-03-23 10:36:11 +00:00
|
|
|
import { is } from "./is";
|
|
|
|
import { Value } from "./values";
|
|
|
|
import { Set, Dictionary } from "./dictionary";
|
|
|
|
import { Annotated } from "./annotated";
|
|
|
|
import { unannotate } from "./strip";
|
2021-05-17 12:54:06 +00:00
|
|
|
import { embed, isEmbedded, Embedded } from "./embedded";
|
2021-03-23 10:36:11 +00:00
|
|
|
|
|
|
|
export function merge<T>(
|
2021-05-17 12:54:06 +00:00
|
|
|
mergeEmbeddeds: (a: T, b: T) => T | undefined,
|
2021-03-23 10:36:11 +00:00
|
|
|
item0: Value<T>,
|
|
|
|
... items: Array<Value<T>>): Value<T>
|
|
|
|
{
|
|
|
|
function die(): never {
|
|
|
|
throw new Error("Cannot merge items");
|
|
|
|
}
|
|
|
|
|
|
|
|
function walk(a: Value<T>, b: Value<T>): Value<T> {
|
|
|
|
if (a === b) return a;
|
|
|
|
return fold<T, Value<T>>(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<Value<T>, Tuple<Value<T>>, T>) {
|
|
|
|
if (!Record.isRecord<Value<T>, Tuple<Value<T>>, T>(b)) die();
|
|
|
|
return Record(walk(r.label, b.label), walkMany(r, b));
|
|
|
|
},
|
|
|
|
array(a: Array<Value<T>>) {
|
|
|
|
if (!Array.isArray(b) || Record.isRecord(b)) die();
|
|
|
|
return walkMany(a, b);
|
|
|
|
},
|
|
|
|
set(_s: Set<T>) { die(); },
|
|
|
|
dictionary(d: Dictionary<T>) {
|
|
|
|
if (!Dictionary.isDictionary<T>(b)) die();
|
|
|
|
const r = new Dictionary<T>();
|
|
|
|
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<T>) {
|
|
|
|
return walk(a, unannotate(b));
|
|
|
|
},
|
|
|
|
|
2021-05-17 12:54:06 +00:00
|
|
|
embedded(t: Embedded<T>) {
|
|
|
|
if (!isEmbedded<T>(b)) die();
|
|
|
|
const r = mergeEmbeddeds(t.embeddedValue, b.embeddedValue);
|
2021-03-23 10:36:11 +00:00
|
|
|
if (r === void 0) die();
|
2021-04-24 19:59:52 +00:00
|
|
|
return embed(r);
|
2021-03-23 10:36:11 +00:00
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function walkMany(a: Array<Value<T>>, b: Array<Value<T>>): Array<Value<T>> {
|
|
|
|
if (a.length !== b.length) die();
|
|
|
|
return a.map((aa, i) => walk(aa, b[i]));
|
|
|
|
}
|
|
|
|
|
|
|
|
return items.reduce(walk, item0);
|
|
|
|
}
|