import { is, isAnnotated } from './is'; import { Bytes } from './bytes'; import { Set, Dictionary } from './dictionary'; import { Embedded, isEmbedded } from './embedded'; import { Float } from './float'; import { Value } from './values'; import { Record } from './record'; export function typeCode(v: Value): number { if (isAnnotated(v)) v = v.item; switch (typeof v) { case 'boolean': return 0; case 'number': case 'bigint': return 3; case 'string': return 4; case 'symbol': return 6; case 'object': if (Float.isFloat(v)) return 2; // 1 was for single-precision floats if (Bytes.isBytes(v)) return 5; if (Array.isArray(v)) { return ('label' in v) ? 7 : 8; } if (Set.isSet(v)) return 9; if (Dictionary.isDictionary(v)) return 10; if (isEmbedded(v)) return 11; /* fall through */ default: throw new Error("Invalid Value in typeCode"); } } export function compare( a: Value, b: Value, compare_embedded: (a: V, b: V) => number = (a, b) => is(a, b) ? 0 : a < b ? -1 : 1, ): number { function cmp(a: Value, b: Value): number { if (isAnnotated(a)) a = a.item; if (isAnnotated(b)) b = b.item; const ta = typeCode(a); const tb = typeCode(b); if (ta < tb) return -1; if (ta > tb) return 1; switch (ta) { case 0: case 3: case 4: { const va = a as any; const vb = b as any; return va < vb ? -1 : va > vb ? 1 : 0; } // case 1: // was single-precision case 2: { const va = (a as Float).value; const vb = (b as Float).value; return va < vb ? -1 : va > vb ? 1 : 0; } case 5: return Bytes.compare(a as Bytes, b as Bytes); case 6: { const va = (a as symbol).description!; const vb = (b as symbol).description!; return va < vb ? -1 : va > vb ? 1 : 0; } case 7: { const lr = cmp((a as Record, Value[], V>).label, (b as Record, Value[], V>).label); if (lr !== 0) return lr; /* fall through */ } case 8: { const va = a as Value[]; const vb = b as Value[]; const l = Math.min(va.length, vb.length) for (let i = 0; i < l; i++) { const c = cmp(va[i], vb[i]); if (c !== 0) return c; } return va.length < vb.length ? -1 : va.length > vb.length ? 1 : 0; } case 9: { const va = Array.from(a as Set).sort(cmp); const vb = Array.from(b as Set).sort(cmp); return cmp(va, vb); } case 10: { const va = Array.from(a as Dictionary).sort(cmp); const vb = Array.from(b as Dictionary).sort(cmp); return cmp(va, vb); } case 11: return compare_embedded((a as Embedded).embeddedValue, (b as Embedded).embeddedValue); default: throw new Error("Invalid typeCode: " + ta); } } return cmp(a, b); }