From efdf9e3d5447a7ea535a764853645537353963d9 Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Mon, 12 Sep 2016 23:59:30 -0400 Subject: [PATCH] slotted interface --- ent/class.go | 8 ++++++-- ent/decoders.go | 6 ++++-- ent/dict.go | 24 ++++++++++++------------ ent/entity.go | 46 +++++----------------------------------------- ent/field.go | 3 +++ ent/selection.go | 35 +++++++++++++++++++++++++++++------ ent/slotted.go | 25 +++++++++++++++++++++++++ 7 files changed, 84 insertions(+), 63 deletions(-) create mode 100644 ent/slotted.go diff --git a/ent/class.go b/ent/class.go index 8669f74..b38e53b 100644 --- a/ent/class.go +++ b/ent/class.go @@ -19,8 +19,12 @@ type Class struct { fieldNames map[string]int } -func (c *Class) New() *Entity { - return &Entity{Class: c} +func (c *Class) New(serial int) *Entity { + return &Entity{ + Class: c, + slots: make([]interface{}, len(c.Fields)), + serial: serial, + } } func (c Class) String() string { diff --git a/ent/decoders.go b/ent/decoders.go index bcaacd6..65170b3 100644 --- a/ent/decoders.go +++ b/ent/decoders.go @@ -14,7 +14,9 @@ type decoder func(bit.Reader) interface{} func newFieldDecoder(n *Namespace, f *Field) decoder { Debug.Printf("new decoder: type: %s name: %s sendNode: %s\n\tbits: %d low: %v high: %v\n\tflags: %d serializer: %v serializerVersion: %v\n\tclass: %v encoder: %v", f._type, f.name, f.sendNode, f.bits, f.low, f.high, f.flags, f.serializer, f.serializerVersion, f.class, f.encoder) - switch f._type.String() { + typeName := f._type.String() + + switch typeName { case "bool": return decodeBool case "uint8", "uint16", "uint32", "uint64", "Color": @@ -33,7 +35,7 @@ func newFieldDecoder(n *Namespace, f *Field) decoder { } switch { - case strings.HasPrefix(f._type.String(), "CHandle"): + case strings.HasPrefix(typeName, "CHandle"): return decodeVarInt32 } return nil diff --git a/ent/dict.go b/ent/dict.go index b6b1f8c..faf153c 100644 --- a/ent/dict.go +++ b/ent/dict.go @@ -36,7 +36,7 @@ const e_limit = 2048 // be used on the client. type Dict struct { *Namespace - entities []Entity + entities []*Entity br *bit.BufReader sr *selectionReader @@ -49,7 +49,7 @@ type Dict struct { func NewDict(sd *stbl.Dict) *Dict { d := &Dict{ Namespace: new(Namespace), - entities: make([]Entity, e_limit), + entities: make([]*Entity, e_limit), br: new(bit.BufReader), sr: new(selectionReader), base: sd.TableForName("instancebaseline"), @@ -65,7 +65,7 @@ func (d *Dict) createEntity(id int) error { if len(d.Namespace.classes) == 0 { return fmt.Errorf("unable to create entity %d: namespace has no classes", id) } - d.br.ReadBits(17) // ??? + serial := int(d.br.ReadBits(17)) classV := int(bit.ReadVarInt(d.br)) className := d.classIds[classId] class := d.Class(className, classV) @@ -73,9 +73,9 @@ func (d *Dict) createEntity(id int) error { return fmt.Errorf("unable to create entity %d: no class found for class name %s, version %d", className, classV) } Debug.Printf("create entity id: %d classId: %d className: %v class: %v\n", id, classId, className, class) - e := class.New() - e.Read(d.br, d.sr) - return nil + e := class.New(serial) + d.entities[id] = e + return fillSlots(e, d.sr, d.br) } func (d *Dict) getEntity(id int) *Entity { @@ -83,7 +83,7 @@ func (d *Dict) getEntity(id int) *Entity { Debug.Printf("edict refused getEntity request for invalid id %d", id) return nil } - return &d.entities[id] + return d.entities[id] } func (d *Dict) updateEntity(id int) error { @@ -92,7 +92,7 @@ func (d *Dict) updateEntity(id int) error { if e == nil { return fmt.Errorf("update entity %d refused: no such entity", id) } - e.Read(d.br, d.sr) + // e.Read(d.br, d.sr) return nil } @@ -101,7 +101,7 @@ func (d *Dict) deleteEntity(id int) error { if id < 0 || id >= e_limit { return fmt.Errorf("delete entity %d refused: no such entity", id) } - d.entities[id] = Entity{} + d.entities[id] = nil return nil } @@ -190,7 +190,7 @@ func (d *Dict) syncBaselines() { } if c.baseline == nil { - c.baseline = c.New() + c.baseline = c.New(-1) } if e.Value == nil || len(e.Value) == 0 { @@ -200,8 +200,8 @@ func (d *Dict) syncBaselines() { d.br.SetSource(e.Value) Debug.Printf("syncBaselines has new baseline for class %v", c) - if err := c.baseline.Read(d.br, d.sr); err != nil { - Debug.Printf("syncBaselines failed to read a baseline: %v", err) + if err := fillSlots(c.baseline, d.sr, d.br); err != nil { + Debug.Printf("syncBaselines failed to fill a baseline: %v", err) continue } } diff --git a/ent/entity.go b/ent/entity.go index 6a16256..8af22bd 100644 --- a/ent/entity.go +++ b/ent/entity.go @@ -1,47 +1,11 @@ package ent -import ( - "fmt" - - "github.com/jordanorelli/hyperstone/bit" -) - type Entity struct { *Class - slots []interface{} + serial int + slots []interface{} } -func (e *Entity) Read(br bit.Reader, sr *selectionReader) error { - if e.Class == nil { - return fmt.Errorf("unable to read entity: entity has no class") - } - Debug.Printf("entity %v read", e) - - if err := sr.read(br, htree); err != nil { - return fmt.Errorf("unable to read entity: %v", err) - } - - for _, s := range sr.selections() { - switch s.count { - case 0: - panic("field selection makes no sense") - case 1: - Debug.Printf("direct selection: %v", s.path()) - field := e.Class.Fields[s.vals[0]] - Debug.Printf("field: %v", e.Class.Fields[s.vals[0]]) - fn := field.decoder - if fn == nil { - Info.Fatalf("field has no decoder: %v", field) - } - v, err := fn(br), br.Err() - Debug.Printf("value: %v err: %v", v, err) - if err != nil { - Info.Fatalf("field decode error: %v", err) - } - default: - Debug.Printf("child selection: %v", s.path()) - return fmt.Errorf("child selections aren't done yet") - } - } - return nil -} +func (e *Entity) getSlotValue(n int) interface{} { return e.slots[n] } +func (e *Entity) setSlotValue(n int, v interface{}) { e.slots[n] = v } +func (e *Entity) getSlotDecoder(n int) decoder { return e.Class.Fields[n].decoder } diff --git a/ent/field.go b/ent/field.go index c24159d..95dd15e 100644 --- a/ent/field.go +++ b/ent/field.go @@ -20,6 +20,9 @@ type Field struct { class *Class // source class on which the field was originally defined encoder *Symbol // binary encoder, named explicitly in protobuf decoder // decodes field values from a bit stream + isTemplate bool // whether or not the field is a template type + templateType string + elemType string } func (f Field) String() string { diff --git a/ent/selection.go b/ent/selection.go index cd20dc0..6720987 100644 --- a/ent/selection.go +++ b/ent/selection.go @@ -18,6 +18,31 @@ type selection struct { func (s selection) path() []int { return s.vals[:s.count] } +func (s selection) fill(dest slotted, br bit.Reader) error { + Debug.Printf("fill selection %v", s) + switch s.count { + case 0: + panic("selection makes no sense") + case 1: + fn := dest.getSlotDecoder(s.vals[0]) + if fn == nil { + switch v := dest.(type) { + case *Entity: + Info.Fatalf("%v entity has no decoder for slot %d (%v)", v.Class, s.vals[0], v.Class.Fields[s.vals[0]]) + default: + Info.Fatalf("slotted value %v has no decoder for slot %d", dest, s.vals[0]) + } + } + val := fn(br) + old := dest.getSlotValue(s.vals[0]) + dest.setSlotValue(s.vals[0], val) + Debug.Printf("%v -> %v", old, val) + return nil + default: + return fmt.Errorf("child selections aren't done yet") + } +} + // selectionReader reads a set of field selections off of the wire. the // selections are represented as arrays of slot positions to be traversed in // order to select an entity slot. @@ -33,25 +58,23 @@ type selectionReader struct { all [1024]selection } -func (r *selectionReader) read(br bit.Reader, n node) error { +func (r *selectionReader) readSelections(br bit.Reader, n node) ([]selection, error) { r.cur.count = 1 r.cur.vals[0] = -1 r.count = 0 for fn := walk(n, br); fn != nil; fn = walk(n, br) { if err := br.Err(); err != nil { - return fmt.Errorf("unable to read selection: bit reader error: %v", err) + return nil, fmt.Errorf("unable to read selection: bit reader error: %v", err) } fn(r, br) r.keep() } if err := br.Err(); err != nil { - return fmt.Errorf("unable to read selection: bit reader error: %v", err) + return nil, fmt.Errorf("unable to read selection: bit reader error: %v", err) } - return nil + return r.all[:r.count], nil } -func (r *selectionReader) selections() []selection { return r.all[:r.count] } - // adds i to the current selection func (r *selectionReader) add(i int) { r.cur.vals[r.cur.count-1] += i diff --git a/ent/slotted.go b/ent/slotted.go new file mode 100644 index 0000000..3666524 --- /dev/null +++ b/ent/slotted.go @@ -0,0 +1,25 @@ +package ent + +import ( + "github.com/jordanorelli/hyperstone/bit" +) + +type slotted interface { + getSlotValue(int) interface{} + setSlotValue(int, interface{}) + getSlotDecoder(int) decoder +} + +func fillSlots(dest slotted, sr *selectionReader, br bit.Reader) error { + selections, err := sr.readSelections(br, htree) + if err != nil { + return err + } + + for _, s := range selections { + if err := s.fill(dest, br); err != nil { + return err + } + } + return nil +}