Fix canonical encoding of Set and Dictionary

This commit is contained in:
Tony Garnock-Jones 2021-03-05 21:14:15 +01:00
parent 4022b76650
commit a05bf0cb7a
2 changed files with 14 additions and 14 deletions

View File

@ -60,10 +60,16 @@ export class Dictionary<V, T extends object = DefaultPointer> extends FlexMap<Va
[PreserveOn](encoder: Encoder<T>) {
if (encoder.canonical) {
const pieces = Array.from(this).map(([k, v]) =>
Bytes.concat([canonicalEncode(k), canonicalEncode(v)]));
pieces.sort(Bytes.compare);
encoder.encoderawvalues(Tag.Dictionary, pieces);
const entries = Array.from(this);
const pieces = entries.map<[Bytes, number]>(([k, _v], i) => [canonicalEncode(k), i]);
pieces.sort((a, b) => Bytes.compare(a[0], b[0]));
encoder.emitbyte(Tag.Dictionary);
pieces.forEach(([_encodedKey, i]) => {
const [k, v] = entries[i];
encoder.push(k);
encoder.push(v as unknown as Value<T>); // Suuuuuuuper unsound
});
encoder.emitbyte(Tag.End);
} else {
encoder.emitbyte(Tag.Dictionary);
this.forEach((v, k) => {
@ -116,9 +122,9 @@ export class Set<T extends object = DefaultPointer> extends FlexSet<Value<T>> {
[PreserveOn](encoder: Encoder<T>) {
if (encoder.canonical) {
const pieces = Array.from(this).map(k => canonicalEncode(k));
pieces.sort(Bytes.compare);
encoder.encoderawvalues(Tag.Set, pieces);
const pieces = Array.from(this).map<[Bytes, Value<T>]>(k => [canonicalEncode(k), k]);
pieces.sort((a, b) => Bytes.compare(a[0], b[0]));
encoder.encodevalues(Tag.Set, pieces.map(e => e[1]));
} else {
encoder.encodevalues(Tag.Set, this);
}

View File

@ -1,5 +1,5 @@
import { Tag } from "./constants";
import { Bytes, BytesLike, underlying } from "./bytes";
import { Bytes } from "./bytes";
import { Value } from "./values";
import { PreserveOn } from "./symbols";
import { EncodeError } from "./codec";
@ -137,12 +137,6 @@ export class Encoder<T extends object> {
this.emitbyte(Tag.End);
}
encoderawvalues(tag: Tag, items: BytesLike[]) {
this.emitbyte(tag);
items.forEach((i) => this.emitbytes(underlying(i)));
this.emitbyte(Tag.End);
}
push(v: Encodable<T>) {
if (isPreservable<never>(v)) {
v[PreserveOn](this as unknown as Encoder<never>);