(js2) Minimal support for decoding structs

This commit is contained in:
Rafael Weinstein
2015-10-29 11:19:01 -07:00
parent 214860c2ad
commit dbd8391929
6 changed files with 321 additions and 49 deletions

View File

@@ -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};

View File

@@ -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);
});
});

View File

@@ -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};

View File

@@ -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
View 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};

View File

@@ -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};