mirror of
https://github.com/dolthub/dolt.git
synced 2026-02-04 10:25:17 -06:00
(js2) Minimal support for decoding structs
This commit is contained in:
@@ -2,11 +2,13 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import {isPrimitiveKind, Kind} from './noms_kind.js';
|
||||
import {makeCompoundTypeRef, makePrimitiveTypeRef, makeTypeRef, TypeRef} from './type_ref.js';
|
||||
import Ref from './ref.js';
|
||||
import type {ChunkStore} from './chunk_store.js';
|
||||
import type {NomsKind} from './noms_kind.js';
|
||||
import {isPrimitiveKind, Kind} from './noms_kind.js';
|
||||
import {makeCompoundTypeRef, makePrimitiveTypeRef, makeTypeRef, StructDesc, TypeRef} from './type_ref.js';
|
||||
import {lookupPackage, Package} from './package.js';
|
||||
|
||||
|
||||
class JsonArrayReader {
|
||||
_a: Array<any>;
|
||||
@@ -108,7 +110,7 @@ class JsonArrayReader {
|
||||
throw new Error('Unreachable');
|
||||
}
|
||||
|
||||
readList(t: TypeRef, pkg: ?Ref): Array<any> {
|
||||
readList(t: TypeRef, pkg: ?Package): Array<any> {
|
||||
let elemType = t.elemTypes[0];
|
||||
let list = [];
|
||||
while (!this.atEnd()) {
|
||||
@@ -118,7 +120,7 @@ class JsonArrayReader {
|
||||
return list;
|
||||
}
|
||||
|
||||
readSet(t: TypeRef, pkg: ?Ref): Set {
|
||||
readSet(t: TypeRef, pkg: ?Package): Set {
|
||||
let elemType = t.elemTypes[0];
|
||||
let s = new Set();
|
||||
while (!this.atEnd()) {
|
||||
@@ -129,7 +131,7 @@ class JsonArrayReader {
|
||||
return s;
|
||||
}
|
||||
|
||||
readMap(t: TypeRef, pkg: ?Ref): Map {
|
||||
readMap(t: TypeRef, pkg: ?Package): Map {
|
||||
let keyType = t.elemTypes[0];
|
||||
let valueType = t.elemTypes[1];
|
||||
let m = new Map();
|
||||
@@ -147,7 +149,7 @@ class JsonArrayReader {
|
||||
return this.readValueWithoutTag(t);
|
||||
}
|
||||
|
||||
readValueWithoutTag(t: TypeRef, pkg: ?Ref = null): any {
|
||||
readValueWithoutTag(t: TypeRef, pkg: ?Package = null): any {
|
||||
// TODO: Verify read values match tagged kinds.
|
||||
switch (t.kind) {
|
||||
case Kind.Blob:
|
||||
@@ -192,11 +194,70 @@ class JsonArrayReader {
|
||||
throw new Error('Not allowed');
|
||||
case Kind.TypeRef:
|
||||
case Kind.Unresolved:
|
||||
throw new Error('Not implemented');
|
||||
return this.readUnresolvedKindToValue(t, pkg);
|
||||
}
|
||||
|
||||
throw new Error('Unreached');
|
||||
}
|
||||
|
||||
readUnresolvedKindToValue(t: TypeRef, pkg: ?Package = null): any {
|
||||
let pkgRef = t.packageRef;
|
||||
let ordinal = t.ordinal;
|
||||
if (!pkgRef.isEmpty()) {
|
||||
let pkg2 = lookupPackage(pkgRef);
|
||||
if (!pkg2) {
|
||||
throw new Error('Not implemented');
|
||||
} else {
|
||||
pkg = pkg2;
|
||||
}
|
||||
}
|
||||
|
||||
if (pkg) {
|
||||
let typeDef = pkg.types[ordinal];
|
||||
if (typeDef.kind === Kind.Enum) {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
if (typeDef.kind !== Kind.Struct) {
|
||||
throw new Error('Attempt to resolve non-struct struct kind');
|
||||
}
|
||||
|
||||
return this.readStruct(typeDef, t, pkg);
|
||||
} else {
|
||||
throw new Error('Woah, got a null pkg. pkgRef: ' + pkgRef.toString() + ' ordinal: ' + ordinal);
|
||||
}
|
||||
}
|
||||
|
||||
readStruct(typeDef: TypeRef, typeRef: TypeRef, pkg: Package): any {
|
||||
// TODO FixupTypeRef?
|
||||
let desc = typeDef.desc;
|
||||
if (desc instanceof StructDesc) {
|
||||
let s = Object.create(null);
|
||||
|
||||
for (let i = 0; i < desc.fields.length; i++) {
|
||||
let field = desc.fields[i];
|
||||
|
||||
if (field.optional) {
|
||||
let b = this.readBool();
|
||||
if (b) {
|
||||
let v = this.readValueWithoutTag(field.t, pkg);
|
||||
s[field.name] = v;
|
||||
}
|
||||
} else {
|
||||
let v = this.readValueWithoutTag(field.t, pkg);
|
||||
s[field.name] = v;
|
||||
}
|
||||
}
|
||||
|
||||
if (desc.union.length > 0) {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
return s;
|
||||
} else {
|
||||
throw new Error('Attempt to read struct without StructDesc typeref');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {JsonArrayReader};
|
||||
export {JsonArrayReader};
|
||||
|
||||
@@ -2,14 +2,15 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import {assert} from 'chai';
|
||||
import {JsonArrayReader} from './decode.js';
|
||||
import {Kind} from './noms_kind.js';
|
||||
import {suite} from 'mocha';
|
||||
import {TypeRef, makePrimitiveTypeRef, makeCompoundTypeRef, makeTypeRef} from './type_ref.js';
|
||||
import MemoryStore from './memory_store.js';
|
||||
import Ref from './ref.js';
|
||||
import test from './async_test.js';
|
||||
import {assert} from 'chai';
|
||||
import {JsonArrayReader} from './decode.js';
|
||||
import {Kind} from './noms_kind.js';
|
||||
import {registerPackage, Package} from './package.js';
|
||||
import {suite} from 'mocha';
|
||||
import {Field, makeCompoundTypeRef, makePrimitiveTypeRef, makeStructTypeRef, makeTypeRef, TypeRef} from './type_ref.js';
|
||||
|
||||
suite('Decode', () => {
|
||||
test('read', async () => {
|
||||
@@ -167,4 +168,21 @@ suite('Decode', () => {
|
||||
|
||||
assertSetsEqual(s, v);
|
||||
});
|
||||
|
||||
test('test read struct', async () => {
|
||||
let ms = new MemoryStore();
|
||||
let tr = makeStructTypeRef('A1', [
|
||||
new Field('x', makePrimitiveTypeRef(Kind.Int16), false),
|
||||
new Field('s', makePrimitiveTypeRef(Kind.String), false),
|
||||
new Field('b', makePrimitiveTypeRef(Kind.Bool), false)
|
||||
], []);
|
||||
|
||||
let pkg = new Package([tr], []);
|
||||
registerPackage(pkg);
|
||||
|
||||
let a = [Kind.Unresolved, pkg.ref.toString(), 0, 42, 'hi', true];
|
||||
let r = new JsonArrayReader(a, ms);
|
||||
let v = r.readTopLevelValue();
|
||||
assert.deepEqual({x: 42, s: 'hi', b: true}, v);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {ChunkStore} from './chunk_store.js';
|
||||
import type {NomsKind} from './noms_kind.js';
|
||||
|
||||
import Chunk from './chunk.js';
|
||||
import MemoryStore from './memory_store.js';
|
||||
import {Kind} from './noms_kind.js';
|
||||
import {TypeRef} from './type_ref.js';
|
||||
import Ref from './ref.js';
|
||||
import type {ChunkStore} from './chunk_store.js';
|
||||
import type {NomsKind} from './noms_kind.js';
|
||||
import {isPrimitiveKind, Kind} from './noms_kind.js';
|
||||
import {makePrimitiveTypeRef, StructDesc, TypeRef} from './type_ref.js';
|
||||
import {Package} from './package.js';
|
||||
|
||||
const typedTag = 't ';
|
||||
|
||||
@@ -29,6 +30,10 @@ class JsonArrayWriter {
|
||||
this.write(k);
|
||||
}
|
||||
|
||||
writeRef(r: Ref) {
|
||||
this.write(r.toString());
|
||||
}
|
||||
|
||||
writeTypeRefAsTag(t: TypeRef) {
|
||||
let k = t.kind;
|
||||
this.writeKind(k);
|
||||
@@ -75,43 +80,24 @@ class JsonArrayWriter {
|
||||
this.write(v); // TODO: Verify value fits in type
|
||||
break;
|
||||
case Kind.List: {
|
||||
let w2 = new JsonArrayWriter(this._cs);
|
||||
let elemType = t.elemTypes[0];
|
||||
if (v instanceof Array) {
|
||||
let w2 = new JsonArrayWriter(this._cs);
|
||||
let elemType = t.elemTypes[0];
|
||||
for (let i = 0; i < v.length; i++) {
|
||||
w2.writeValue(v[i], elemType);
|
||||
}
|
||||
this.write(w2.array);
|
||||
} else {
|
||||
throw new Error('Attempt to serialize non-list as list');
|
||||
}
|
||||
|
||||
this.write(w2.array);
|
||||
break;
|
||||
}
|
||||
case Kind.Set: {
|
||||
let w2 = new JsonArrayWriter(this._cs);
|
||||
let elemType = t.elemTypes[0];
|
||||
if (v instanceof Set) {
|
||||
let elems = [];
|
||||
v.forEach(v => {
|
||||
elems.push(v);
|
||||
});
|
||||
elems = orderValuesByRef(elemType, elems);
|
||||
for (let i = 0; i < elems.length; i++) {
|
||||
w2.writeValue(elems[i], elemType);
|
||||
}
|
||||
} else {
|
||||
throw new Error('Attempt to serialize non-set as set');
|
||||
}
|
||||
|
||||
this.write(w2.array);
|
||||
break;
|
||||
}
|
||||
case Kind.Map: {
|
||||
let w2 = new JsonArrayWriter(this._cs);
|
||||
let keyType = t.elemTypes[0];
|
||||
let valueType = t.elemTypes[1];
|
||||
if (v instanceof Map) {
|
||||
let w2 = new JsonArrayWriter(this._cs);
|
||||
let keyType = t.elemTypes[0];
|
||||
let valueType = t.elemTypes[1];
|
||||
let elems = [];
|
||||
v.forEach((v, k) => {
|
||||
elems.push(k);
|
||||
@@ -121,15 +107,114 @@ class JsonArrayWriter {
|
||||
w2.writeValue(elems[i], keyType);
|
||||
w2.writeValue(v.get(elems[i]), valueType);
|
||||
}
|
||||
this.write(w2.array);
|
||||
} else {
|
||||
throw new Error('Attempt to serialize non-map as maps');
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Kind.Package: {
|
||||
if (v instanceof Package) {
|
||||
let ptr = makePrimitiveTypeRef(Kind.TypeRef);
|
||||
let w2 = new JsonArrayWriter(this._cs);
|
||||
for (let i = 0; i < v.types.length; i++) {
|
||||
w2.writeValue(v.types[i], ptr);
|
||||
}
|
||||
this.write(w2.array);
|
||||
let w3 = new JsonArrayWriter(this._cs);
|
||||
for (let i = 0; i < v.dependencies.length; i++) {
|
||||
w3.writeRef(v.dependencies[i]);
|
||||
}
|
||||
this.write(w3.array);
|
||||
} else {
|
||||
throw new Error('Attempt to serialize non-package as package');
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Kind.Set: {
|
||||
if (v instanceof Set) {
|
||||
let w2 = new JsonArrayWriter(this._cs);
|
||||
let elemType = t.elemTypes[0];
|
||||
let elems = [];
|
||||
v.forEach(v => {
|
||||
elems.push(v);
|
||||
});
|
||||
elems = orderValuesByRef(elemType, elems);
|
||||
for (let i = 0; i < elems.length; i++) {
|
||||
w2.writeValue(elems[i], elemType);
|
||||
}
|
||||
this.write(w2.array);
|
||||
} else {
|
||||
throw new Error('Attempt to serialize non-set as set');
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Kind.TypeRef:
|
||||
if (v instanceof TypeRef) {
|
||||
this.writeTypeRefAsValue(v);
|
||||
} else {
|
||||
throw new Error('Attempt to serialize non-typeref as typeref');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
writeTypeRefAsValue(t: TypeRef) {
|
||||
let k = t.kind;
|
||||
this.writeKind(k);
|
||||
switch (k) {
|
||||
case Kind.Enum:
|
||||
throw new Error('Not implemented');
|
||||
case Kind.List:
|
||||
case Kind.Map:
|
||||
case Kind.Ref:
|
||||
case Kind.Set: {
|
||||
this.write(t.name);
|
||||
let w2 = new JsonArrayWriter(this._cs);
|
||||
for (let i = 0; t.elemTypes.length; i++) {
|
||||
w2.writeTypeRefAsValue(t.elemTypes[i]);
|
||||
}
|
||||
this.write(w2.array);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
case Kind.Struct: {
|
||||
let desc = t.desc;
|
||||
if (desc instanceof StructDesc) {
|
||||
this.write(t.name);
|
||||
let fieldWriter = new JsonArrayWriter(this._cs);
|
||||
for (let i = 0; i < desc.fields.length; i++) {
|
||||
let field = desc.fields[i];
|
||||
fieldWriter.write(field.name);
|
||||
fieldWriter.writeTypeRefAsValue(field.t);
|
||||
fieldWriter.write(field.optional);
|
||||
}
|
||||
this.write(fieldWriter.array);
|
||||
let choiceWriter = new JsonArrayWriter(this._cs);
|
||||
for (let i = 0; i < desc.union.length; i++) {
|
||||
let choice = desc.union[i];
|
||||
choiceWriter.write(choice.name);
|
||||
choiceWriter.writeTypeRefAsValue(choice.t);
|
||||
choiceWriter.write(choice.optional);
|
||||
}
|
||||
this.write(choiceWriter.array);
|
||||
} else {
|
||||
throw new Error('Attempt to serialize non-struct typeref as struct type-ref');
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Kind.Unresolved:
|
||||
throw new Error('Not implemented');
|
||||
default: {
|
||||
if (!isPrimitiveKind(k)) {
|
||||
throw new Error('Not implemented.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,10 +233,16 @@ function orderValuesByRef(t: TypeRef, a: Array<any>): Array<any> {
|
||||
}
|
||||
|
||||
function encodeNomsValue(v: any, t: TypeRef): Chunk {
|
||||
// if (v instanceof Package) {
|
||||
// if (v.dependencies.length > 0) {
|
||||
// throw new Error('Not implemented');
|
||||
// }
|
||||
// }
|
||||
|
||||
let ms = new MemoryStore(); // TODO: This should be passed in.
|
||||
let w = new JsonArrayWriter(ms);
|
||||
w.writeTopLevel(t, v);
|
||||
return new Chunk(typedTag + JSON.stringify(w.array));
|
||||
}
|
||||
|
||||
module.exports = {JsonArrayWriter};
|
||||
export {encodeNomsValue, JsonArrayWriter};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import Chunk from './chunk.js';
|
||||
import Ref from './ref.js';
|
||||
|
||||
class MemoryStore {
|
||||
export default class MemoryStore {
|
||||
_data: { [key: string]: Chunk };
|
||||
_root: Ref;
|
||||
|
||||
@@ -50,5 +50,3 @@ class MemoryStore {
|
||||
|
||||
close() {}
|
||||
}
|
||||
|
||||
module.exports = MemoryStore;
|
||||
|
||||
45
js2/src/package.js
Normal file
45
js2/src/package.js
Normal file
@@ -0,0 +1,45 @@
|
||||
/* @flow */
|
||||
|
||||
'use strict';
|
||||
|
||||
import Ref from './ref.js';
|
||||
import {Kind} from './noms_kind.js';
|
||||
import {makePrimitiveTypeRef, TypeRef} from './type_ref.js';
|
||||
import {encodeNomsValue} from './encode.js';
|
||||
|
||||
const packageTypeRef = makePrimitiveTypeRef(Kind.Package);
|
||||
|
||||
class Package {
|
||||
types: Array<TypeRef>;
|
||||
dependencies: Array<Ref>;
|
||||
_ref: Ref;
|
||||
|
||||
constructor(types: Array<TypeRef>, dependencies: Array<Ref>) {
|
||||
this.types = types;
|
||||
this.dependencies = dependencies;
|
||||
}
|
||||
|
||||
get ref(): Ref {
|
||||
if (!this._ref) {
|
||||
this._ref = encodeNomsValue(this, this.typeRef).ref;
|
||||
}
|
||||
return this._ref;
|
||||
}
|
||||
|
||||
get typeRef(): TypeRef {
|
||||
return packageTypeRef;
|
||||
}
|
||||
}
|
||||
|
||||
const packageRegistry: { [key: string]: Package } = Object.create(null);
|
||||
|
||||
function lookupPackage(r: Ref): ?Package {
|
||||
return packageRegistry[r.toString()];
|
||||
}
|
||||
|
||||
// TODO: Compute ref rather than setting
|
||||
function registerPackage(p: Package) {
|
||||
packageRegistry[p.ref.toString()] = p;
|
||||
}
|
||||
|
||||
export {lookupPackage, Package, registerPackage};
|
||||
@@ -71,6 +71,61 @@ class CompoundDesc {
|
||||
}
|
||||
}
|
||||
|
||||
class StructDesc {
|
||||
fields: Array<Field>;
|
||||
union: Array<Field>;
|
||||
|
||||
constructor(fields: Array<Field>, union: Array<Field>) {
|
||||
this.fields = fields;
|
||||
this.union = union;
|
||||
}
|
||||
|
||||
get kind(): NomsKind {
|
||||
return Kind.Struct;
|
||||
}
|
||||
|
||||
equals(other: TypeDesc): boolean {
|
||||
if (other instanceof StructDesc) {
|
||||
if (this.fields.length !== other.fields.length || this.union.length !== other.union.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.fields.length; i++) {
|
||||
if (!this.fields[i].equals(other.fields[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.union.length; i++) {
|
||||
if (!this.union[i].equals(other.union[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class Field {
|
||||
name: string;
|
||||
t: TypeRef;
|
||||
optional: boolean;
|
||||
|
||||
constructor(name: string, t: TypeRef, optional: boolean) {
|
||||
this.name = name;
|
||||
this.t = t;
|
||||
this.optional = optional;
|
||||
}
|
||||
|
||||
equals(other: Field): boolean {
|
||||
return this.name === other.name && this.t.equals(other.t) && this.optional === other.optional;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class TypeRef {
|
||||
_namespace: string;
|
||||
_name: string;
|
||||
@@ -192,8 +247,12 @@ function makeCompoundTypeRef(k: NomsKind, ...elemTypes: Array<TypeRef>): TypeRef
|
||||
return buildType('', new CompoundDesc(k, elemTypes));
|
||||
}
|
||||
|
||||
function makeStructTypeRef(name: string, fields: Array<Field>, choices: Array<Field>): TypeRef {
|
||||
return buildType(name, new StructDesc(fields, choices));
|
||||
}
|
||||
|
||||
function makeTypeRef(pkgRef: Ref, ordinal: number): TypeRef {
|
||||
return new TypeRef('', '', new UnresolvedDesc(pkgRef, ordinal));
|
||||
}
|
||||
|
||||
export {CompoundDesc, makeCompoundTypeRef, makePrimitiveTypeRef, makeTypeRef, TypeRef};
|
||||
export {CompoundDesc, Field, makeCompoundTypeRef, makePrimitiveTypeRef, makeStructTypeRef, makeTypeRef, StructDesc, TypeRef};
|
||||
|
||||
Reference in New Issue
Block a user