Skip to content

Commit

Permalink
#18 round trip tests pass for binary graph serialization format
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronc committed Mar 29, 2019
1 parent 44aedfc commit b2d77ad
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 48 deletions.
155 changes: 131 additions & 24 deletions graph/binary/deserialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ import (
"fmt"
"github.com/regen-network/regen-ledger/graph"
"github.com/regen-network/regen-ledger/graph/impl"
"github.com/regen-network/regen-ledger/types"
"github.com/regen-network/regen-ledger/x/schema"
"io"
"math"
)
import sdk "github.com/cosmos/cosmos-sdk/types"

func DeserializeGraph(resolver SchemaResolver, r io.ByteScanner) (g graph.Graph, err error) {
ctx := &dszContext{resolver, r, 0}
Expand All @@ -25,7 +28,7 @@ type dszContext struct {
}

func (ctx *dszContext) readGraph() (g graph.Graph, err error) {
ctx.version = ctx.mustReadUvarint()
ctx.version = ctx.mustReadUvarint64()
haveRootNode := ctx.mustReadByte()
g = impl.NewGraph()
if haveRootNode == 1 {
Expand All @@ -36,7 +39,7 @@ func (ctx *dszContext) readGraph() (g graph.Graph, err error) {
g.WithNode(r)
}
nNodes := ctx.mustReadVarint()
for i := int64(0); i < nNodes; i++ {
for i := 0; i < nNodes; i++ {
n, err := ctx.readNode()
if err != nil {
return nil, err
Expand All @@ -47,23 +50,36 @@ func (ctx *dszContext) readGraph() (g graph.Graph, err error) {
}

func (ctx *dszContext) readNode() (n graph.Node, err error) {
panic("TODO")
//id, err := ctx.readString()
//if err != nil {
// return nil, err
//}
//n, err = ctx.readNodeProperties()
//if err != nil {
// return nil, err
//}
//n.id = id
//return n, nil
id, err := ctx.readID()
if err != nil {
return nil, err
}
n, err = ctx.readNodeProperties()
if err != nil {
return nil, err
}
n.SetID(id)
return n, nil
}

func (ctx *dszContext) readID() (id types.HasURI, err error) {
prefix := ctx.mustReadByte()
switch prefix {
case prefixGeoAddress:
return types.GeoAddress(ctx.readByteSlice()), nil
case prefixAccAddress:
return AccAddressID{sdk.AccAddress(ctx.readByteSlice())}, nil
case prefixHashID:
return HashID{ctx.readString()}, nil
default:
return nil, fmt.Errorf("unexpected ID prefix %d", prefix)
}
}

func (ctx *dszContext) readNodeProperties() (n graph.Node, err error) {
n = impl.NewNode(nil)
nProps := ctx.mustReadVarint()
for i := int64(0); i < nProps; i++ {
for i := 0; i < nProps; i++ {
prop, value, err := ctx.readProperty()
// TODO verify ordering
// hash
Expand All @@ -77,13 +93,10 @@ func (ctx *dszContext) readNodeProperties() (n graph.Node, err error) {

func (ctx *dszContext) readProperty() (prop graph.Property, value interface{}, err error) {
prefix := ctx.mustReadByte()
if prefix != 0 {
if prefix != prefixPropertyID {
return nil, nil, fmt.Errorf("unexpected property ID prefix %d", prefix)
}
id, err := binary.ReadUvarint(ctx.r)
if err != nil {
return nil, nil, err
}
id := ctx.mustReadVarint64()
prop = ctx.resolver.GetPropertyByID(schema.PropertyID(id))
if prop == nil {
return nil, nil, fmt.Errorf("can't resolve property with ID %d", id)
Expand All @@ -96,11 +109,65 @@ func (ctx *dszContext) readProperty() (prop graph.Property, value interface{}, e
}

func (ctx *dszContext) readValue(prop graph.Property) (x interface{}, err error) {
panic("TODO")
switch prop.Arity() {
case graph.One:
return ctx.readOneValue(prop.Type())
case graph.UnorderedSet:
return ctx.readValues(prop.Type())
case graph.OrderedSet:
return ctx.readValues(prop.Type())
default:
panic("unknown arity")
}
}

func (ctx *dszContext) readOneValue(propertyType graph.PropertyType) (interface{}, error) {
switch propertyType {
case graph.TyString:
return ctx.readString(), nil
case graph.TyDouble:
return ctx.readFloat64(), nil
case graph.TyBool:
return ctx.readBool(), nil
case graph.TyInteger:
panic("Can't handle integer values yet")
case graph.TyObject:
panic("Can't handle object values yet")
default:
panic("Unknown PropertyType")
}
}

func (ctx *dszContext) readString() (x string, err error) {
panic("TODO")
func (ctx *dszContext) readValues(propertyType graph.PropertyType) (interface{}, error) {
switch propertyType {
case graph.TyString:
n := ctx.mustReadVarint()
res := make([]string, n)
for i := 0; i < n; i++ {
res[i] = ctx.readString()
}
return res, nil
case graph.TyDouble:
n := ctx.mustReadVarint()
res := make([]float64, n)
for i := 0; i < n; i++ {
res[i] = ctx.readFloat64()
}
return res, nil
case graph.TyBool:
n := ctx.mustReadVarint()
res := make([]bool, n)
for i := 0; i < n; i++ {
res[i] = ctx.readBool()
}
return res, nil
case graph.TyInteger:
panic("Can't handle integer values yet")
case graph.TyObject:
panic("Can't handle object values yet")
default:
panic("Unknown PropertyType")
}
}

func (ctx *dszContext) mustReadByte() byte {
Expand All @@ -111,18 +178,58 @@ func (ctx *dszContext) mustReadByte() byte {
return b
}

func (ctx *dszContext) mustReadUvarint() uint64 {
func (ctx *dszContext) mustReadUvarint64() uint64 {
x, err := binary.ReadUvarint(ctx.r)
if err != nil {
panic(err)
}
return x
}

func (ctx *dszContext) mustReadVarint() int64 {
func (ctx *dszContext) mustReadVarint64() int64 {
x, err := binary.ReadVarint(ctx.r)
if err != nil {
panic(err)
}
return x
}

func (ctx *dszContext) mustReadVarint() int {
return int(ctx.mustReadVarint64())
}

func (ctx *dszContext) readString() string {
return string(ctx.readByteSlice())
}

func (ctx *dszContext) readByteSlice() []byte {
n := ctx.mustReadVarint()
return ctx.readNBytes(n)
}

func (ctx *dszContext) readNBytes(n int) []byte {
res := make([]byte, n)
for i := 0; i < n; i++ {
res[i] = ctx.mustReadByte()
}
return res
}

func (ctx *dszContext) readFloat64() float64 {
bytes := ctx.readNBytes(8)
bits := binary.LittleEndian.Uint64(bytes)
float := math.Float64frombits(bits)
return float
}

func (ctx *dszContext) readBool() bool {
x := ctx.mustReadByte()
switch x {
case 0:
return false
case 1:
return true
default:
panic("unexpected value for bool")
}
}
21 changes: 3 additions & 18 deletions graph/binary/serialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,10 @@ func (s *szContext) serializeGraph(g graph.Graph) error {
}
nodes := g.Nodes()
s.writeVarInt(len(nodes))
var last string
for _, n := range nodes {
if n == nil {
panic("node ID cannot be nil")
}
uri := n.URI().String()
if last != "" {
if uri < last {
panic("nodes not in sorted order") // Node implementation error so panic
}
if last == uri {
panic("duplicate node ID")
}
last = uri
}
err := s.serializeNode(false, g.GetNode(n))
if err != nil {
return err
Expand All @@ -78,12 +67,6 @@ func (s *szContext) serializeNode(root bool, n graph.Node) error {
props := n.Properties()
s.writeVarInt(len(props))
for _, url := range props {
//if root {
// s.hashText.write("_:_\n")
//} else {
// s.hashText.writeIRI(id)
// s.hashText.write("\n")
//}
err := s.writeProperty(s.w, url, n.GetProperty(url))
if err != nil {
return err
Expand All @@ -103,7 +86,7 @@ func (s *szContext) writeID(id types.HasURI) error {
// TODO
case HashID:
s.writeByte(prefixHashID)
s.writeString(id.String())
s.writeString(id.fragment)
default:
return fmt.Errorf("unexpected ID %s", id.String())
}
Expand Down Expand Up @@ -213,6 +196,7 @@ func (s *szContext) writePropertyOne(ty graph.PropertyType, value interface{}) {
case graph.TyObject:
panic("Can't handle object values yet")
default:
panic("Unknown PropertyType")
}
}

Expand Down Expand Up @@ -250,5 +234,6 @@ func (s *szContext) writePropertyMany(ty graph.PropertyType, value interface{},
case graph.TyObject:
panic("Can't handle object values yet")
default:
panic("Unknown PropertyType")
}
}
14 changes: 8 additions & 6 deletions graph/binary/xrb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,14 @@ func (s *TestSuite) TestProperties() {
return false, err
}
g2, err := DeserializeGraph(s.resolver, w)
if err != nil {
return false, err
}
txt2, err := graph.CanonicalString(g1)
if err != nil {
return false, err
}
hash2 := graph.Hash(g2)
s.T().Logf("%s %s", txt1, txt2)
if txt1 != txt2 {
return false, fmt.Errorf("canonical strings do not match")
}
Expand Down Expand Up @@ -305,12 +307,12 @@ func GenValue(arity graph.Arity, propertyType graph.PropertyType) gopter.Gen {
func GenUnorderedSet(propertyType graph.PropertyType) gopter.Gen {
switch propertyType {
case graph.TyString:
return GenSlice(0, 50, gen.AnyString(), reflect.TypeOf([]string{})).
return GenSlice(1, 50, gen.AnyString(), reflect.TypeOf([]string{})).
Map(func(xs []string) []string {
return UniqueSortedStrings(xs)
})
case graph.TyDouble:
return GenSlice(0, 50, gen.Float64(), reflect.TypeOf([]float64{})).
return GenSlice(1, 50, gen.Float64(), reflect.TypeOf([]float64{})).
Map(func(xs []float64) []float64 {
return UniqueSortedFloat64s(xs)
})
Expand All @@ -321,11 +323,11 @@ func GenUnorderedSet(propertyType graph.PropertyType) gopter.Gen {
func GenOrderedSet(propertyType graph.PropertyType) gopter.Gen {
switch propertyType {
case graph.TyString:
return GenSlice(0, 50, gen.AnyString(), reflect.TypeOf([]string{}))
return GenSlice(1, 50, gen.AnyString(), reflect.TypeOf([]string{}))
case graph.TyDouble:
return GenSlice(0, 50, gen.Float64(), reflect.TypeOf([]float64{}))
return GenSlice(1, 50, gen.Float64(), reflect.TypeOf([]float64{}))
case graph.TyBool:
return GenSlice(0, 50, gen.Bool(), reflect.TypeOf([]bool{}))
return GenSlice(1, 50, gen.Bool(), reflect.TypeOf([]bool{}))
default:
panic(fmt.Sprintf("don't know how to handle PropertyType %s", propertyType.String()))
}
Expand Down

0 comments on commit b2d77ad

Please sign in to comment.