Fixed pointer, list, and map serialization after testing nil map types

gql_cataclysm
noah metz 2023-09-05 00:46:49 -06:00
parent e2f34150ef
commit 15793e1415
5 changed files with 126 additions and 30 deletions

@ -273,7 +273,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) {
ev := value.Elem() ev := value.Elem()
elem_value = &ev elem_value = &ev
} }
elem, err := serializeValue(ctx, reflect_type.Elem(), elem_value) elem, err := SerializeValue(ctx, reflect_type.Elem(), elem_value)
if err != nil { if err != nil {
return SerializedValue{}, err return SerializedValue{}, err
} }
@ -286,7 +286,9 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) {
}, nil }, nil
}, func(ctx *Context, value SerializedValue) (reflect.Type, *reflect.Value, SerializedValue, error) { }, func(ctx *Context, value SerializedValue) (reflect.Type, *reflect.Value, SerializedValue, error) {
if value.Data == nil { if value.Data == nil {
elem_type, _, _, err := DeserializeValue(ctx, value) var elem_type reflect.Type
var err error
elem_type, _, value, err = DeserializeValue(ctx, value)
if err != nil { if err != nil {
return nil, nil, SerializedValue{}, err return nil, nil, SerializedValue{}, err
} }
@ -338,14 +340,14 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) {
// Add to the type stack and data stack // Add to the type stack and data stack
field_hash := Hash(FieldNameBase, gv_tag) field_hash := Hash(FieldNameBase, gv_tag)
if value == nil { if value == nil {
field_ser, err := serializeValue(ctx, field.Type, nil) field_ser, err := SerializeValue(ctx, field.Type, nil)
if err != nil { if err != nil {
return SerializedValue{}, err return SerializedValue{}, err
} }
field_values[field_hash] = field_ser field_values[field_hash] = field_ser
} else { } else {
field_value := value.FieldByIndex(field.Index) field_value := value.FieldByIndex(field.Index)
field_ser, err := serializeValue(ctx, field.Type, &field_value) field_ser, err := SerializeValue(ctx, field.Type, &field_value)
if err != nil { if err != nil {
return SerializedValue{}, err return SerializedValue{}, err
} }
@ -573,7 +575,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) {
var type_stack []SerializedType = nil var type_stack []SerializedType = nil
for i := 0; i < value.Len(); i += 1 { for i := 0; i < value.Len(); i += 1 {
val := value.Index(i) val := value.Index(i)
element, err := serializeValue(ctx, reflect_type.Elem(), &val) element, err := SerializeValue(ctx, reflect_type.Elem(), &val)
if err != nil { if err != nil {
return SerializedValue{}, err return SerializedValue{}, err
} }
@ -584,7 +586,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) {
} }
} }
elem, err := serializeValue(ctx, reflect_type.Elem(), nil) elem, err := SerializeValue(ctx, reflect_type.Elem(), nil)
if err != nil { if err != nil {
return SerializedValue{}, err return SerializedValue{}, err
} }
@ -610,7 +612,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) {
return SerializedValue{}, fmt.Errorf("Cannot serialize nil interfaces") return SerializedValue{}, fmt.Errorf("Cannot serialize nil interfaces")
} else { } else {
elem_value := value.Elem() elem_value := value.Elem()
elem, err := serializeValue(ctx, value.Elem().Type(), &elem_value) elem, err := SerializeValue(ctx, value.Elem().Type(), &elem_value)
if err != nil { if err != nil {
return SerializedValue{}, err return SerializedValue{}, err
} }
@ -631,8 +633,87 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) {
err = ctx.RegisterKind(reflect.Map, NewSerializedType("map"), err = ctx.RegisterKind(reflect.Map, NewSerializedType("map"),
func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){
return SerializedValue{}, fmt.Errorf("serialize map unimplemented") var data []byte
type_stack := []SerializedType{ctx_type}
if value == nil {
data = nil
} else if value.IsZero() {
data = []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
} else if value.Len() == 0 {
data = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
} else {
data = make([]byte, 8)
map_size := 0
var key_types, elem_types []SerializedType
map_iter := value.MapRange()
for map_iter.Next() {
map_size += 1
key_reflect := map_iter.Key()
elem_reflect := map_iter.Value()
key_value, err := SerializeValue(ctx, key_reflect.Type(), &key_reflect)
if err != nil {
return SerializedValue{}, err
}
elem_value, err := SerializeValue(ctx, elem_reflect.Type(), &elem_reflect)
if err != nil {
return SerializedValue{}, err
}
data = append(data, key_value.Data...)
data = append(data, elem_value.Data...)
if key_types == nil {
key_types = key_value.TypeStack
elem_types = elem_value.TypeStack
}
}
binary.BigEndian.PutUint64(data[0:8], uint64(map_size))
type_stack = append(type_stack, key_types...)
type_stack = append(type_stack, elem_types...)
return SerializedValue{
type_stack,
data,
}, nil
}
key_value, err := SerializeValue(ctx, reflect_type.Key(), nil)
if err != nil {
return SerializedValue{}, nil
}
elem_value, err := SerializeValue(ctx, reflect_type.Elem(), nil)
if err != nil {
return SerializedValue{}, nil
}
type_stack = append(type_stack, key_value.TypeStack...)
type_stack = append(type_stack, elem_value.TypeStack...)
return SerializedValue{
type_stack,
data,
}, nil
}, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){
if value.Data == nil {
var key_type, elem_type reflect.Type
var err error
key_type, _, value, err = DeserializeValue(ctx, value)
if err != nil {
return nil, nil, value, err
}
elem_type, _, value, err = DeserializeValue(ctx, value)
if err != nil {
return nil, nil, value, err
}
reflect_type := reflect.MapOf(key_type, elem_type)
return reflect_type, nil, value, nil
} else if len(value.Data) < 8 {
} else {
}
return nil, nil, value, fmt.Errorf("deserialize map unimplemented") return nil, nil, value, fmt.Errorf("deserialize map unimplemented")
}) })
if err != nil { if err != nil {
@ -884,7 +965,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) {
var err error var err error
for i := 0; i < value.Len(); i += 1 { for i := 0; i < value.Len(); i += 1 {
val := value.Index(i) val := value.Index(i)
element, err = serializeValue(ctx, reflect_type.Elem(), &val) element, err = SerializeValue(ctx, reflect_type.Elem(), &val)
if err != nil { if err != nil {
return SerializedValue{}, err return SerializedValue{}, err
} }
@ -895,7 +976,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) {
data, data,
}, nil }, nil
} }
element, err := serializeValue(ctx, reflect_type.Elem(), nil) element, err := SerializeValue(ctx, reflect_type.Elem(), nil)
if err != nil { if err != nil {
return SerializedValue{}, err return SerializedValue{}, err
} }
@ -930,7 +1011,10 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) {
value.Data, value.Data,
}, nil }, nil
} else if slice_length == 0x00 { } else if slice_length == 0x00 {
elem_type, _, remaining, err := DeserializeValue(ctx, value) elem_type, _, remaining, err := DeserializeValue(ctx, SerializedValue{
value.TypeStack,
nil,
})
if err != nil { if err != nil {
return nil, nil, SerializedValue{}, err return nil, nil, SerializedValue{}, err
} }

@ -16,7 +16,6 @@ import (
"bytes" "bytes"
"golang.org/x/net/websocket" "golang.org/x/net/websocket"
"github.com/google/uuid" "github.com/google/uuid"
"reflect"
) )
func TestGQLServer(t *testing.T) { func TestGQLServer(t *testing.T) {
@ -240,10 +239,10 @@ func TestGQLDB(t *testing.T) {
}) })
fatalErr(t, err) fatalErr(t, err)
ser1, err := SerializeValue(ctx, reflect.ValueOf(gql)) ser1, err := SerializeAny(ctx, gql)
fatalErr(t, err) fatalErr(t, err)
ctx.Log.Logf("test", "SER_1: \n%+v\n\n", ser1) ctx.Log.Logf("test", "SER_1: \n%+v\n\n", ser1)
ser2, err := SerializeValue(ctx, reflect.ValueOf(u1)) ser2, err := SerializeAny(ctx, u1)
fatalErr(t, err) fatalErr(t, err)
ctx.Log.Logf("test", "SER_2: \n%+v\n\n", ser2) ctx.Log.Logf("test", "SER_2: \n%+v\n\n", ser2)

@ -249,7 +249,7 @@ func nodeLoop(ctx *Context, node *Node) error {
select { select {
case msg := <- node.MsgChan: case msg := <- node.MsgChan:
ctx.Log.Logf("node_msg", "NODE_MSG: %s - %+v", node.ID, msg.Signal) ctx.Log.Logf("node_msg", "NODE_MSG: %s - %+v", node.ID, msg.Signal)
signal_ser, err := SerializeValue(ctx, reflect.ValueOf(msg.Signal)) signal_ser, err := SerializeAny(ctx, msg.Signal)
if err != nil { if err != nil {
ctx.Log.Logf("signal", "SIGNAL_SERIALIZE_ERR: %s - %+v", err, msg.Signal) ctx.Log.Logf("signal", "SIGNAL_SERIALIZE_ERR: %s - %+v", err, msg.Signal)
} }
@ -437,7 +437,7 @@ func (msgs Messages) Add(ctx *Context, source NodeID, principal ed25519.PrivateK
} }
func NewMessage(ctx *Context, dest NodeID, source NodeID, principal ed25519.PrivateKey, signal Signal) (*Message, error) { func NewMessage(ctx *Context, dest NodeID, source NodeID, principal ed25519.PrivateKey, signal Signal) (*Message, error) {
signal_ser, err := SerializeValue(ctx, reflect.ValueOf(signal)) signal_ser, err := SerializeAny(ctx, signal)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -612,7 +612,7 @@ func NewNode(ctx *Context, key ed25519.PrivateKey, node_type NodeType, buffer_si
func WriteNode(ctx *Context, node *Node) error { func WriteNode(ctx *Context, node *Node) error {
ctx.Log.Logf("db", "DB_WRITE: %s", node.ID) ctx.Log.Logf("db", "DB_WRITE: %s", node.ID)
node_serialized, err := SerializeValue(ctx, reflect.ValueOf(node)) node_serialized, err := SerializeAny(ctx, node)
if err != nil { if err != nil {
return err return err
} }

@ -107,18 +107,19 @@ func (value SerializedValue) PopData(n int) ([]byte, SerializedValue, error) {
return data, value, nil return data, value, nil
} }
func SerializeValue(ctx *Context, value reflect.Value) (SerializedValue, error) { func SerializeAny[T any](ctx *Context, value T) (SerializedValue, error) {
val, err := serializeValue(ctx, value.Type(), &value) reflect_value := reflect.ValueOf(value)
ctx.Log.Logf("serialize", "SERIALIZED_VALUE(%+v): %+v - %+v", value.Type(), val.TypeStack, val.Data) return SerializeValue(ctx, reflect_value.Type(), &reflect_value)
return val, err
} }
func serializeValue(ctx *Context, t reflect.Type, value *reflect.Value) (SerializedValue, error) { func SerializeValue(ctx *Context, t reflect.Type, value *reflect.Value) (SerializedValue, error) {
ctx.Log.Logf("serialize", "Serializing: %+v - %+v", t, value)
ctx_type, type_exists := ctx.TypeReflects[t] ctx_type, type_exists := ctx.TypeReflects[t]
var serialize TypeSerialize = nil
if type_exists == true { if type_exists == true {
type_info := ctx.Types[ctx_type] type_info := ctx.Types[ctx_type]
if type_info.Serialize != nil { if type_info.Serialize != nil {
return type_info.Serialize(ctx, ctx_type, t, value) serialize = type_info.Serialize
} }
} }
@ -130,8 +131,13 @@ func serializeValue(ctx *Context, t reflect.Type, value *reflect.Value) (Seriali
ctx_type = kind_info.Type ctx_type = kind_info.Type
} }
return kind_info.Serialize(ctx, ctx_type, t, value) if serialize == nil {
serialize = kind_info.Serialize
}
serialized_value, err := serialize(ctx, ctx_type, t, value)
ctx.Log.Logf("serialize", "Serialized %+v: %+v - %+v", value, serialized_value, err)
return serialized_value, err
} }
func SerializeField(ctx *Context, ext Extension, field_name string) (SerializedValue, error) { func SerializeField(ctx *Context, ext Extension, field_name string) (SerializedValue, error) {
@ -143,7 +149,7 @@ func SerializeField(ctx *Context, ext Extension, field_name string) (SerializedV
if field.IsValid() == false { if field.IsValid() == false {
return SerializedValue{}, fmt.Errorf("%s is not a field in %+v", field_name, ext) return SerializedValue{}, fmt.Errorf("%s is not a field in %+v", field_name, ext)
} else { } else {
return SerializeValue(ctx, field) return SerializeValue(ctx, field.Type(), &field)
} }
} }
@ -187,7 +193,7 @@ func ParseSerializedValue(data []byte) (SerializedValue, []byte, error) {
} }
func DeserializeValue(ctx *Context, value SerializedValue) (reflect.Type, *reflect.Value, SerializedValue, error) { func DeserializeValue(ctx *Context, value SerializedValue) (reflect.Type, *reflect.Value, SerializedValue, error) {
ctx.Log.Logf("serialize", "DeserializeValue: %+v", value) ctx.Log.Logf("serialize", "Deserializing: %+v", value)
var deserialize TypeDeserialize = nil var deserialize TypeDeserialize = nil
var reflect_type reflect.Type = nil var reflect_type reflect.Type = nil
@ -211,8 +217,6 @@ func DeserializeValue(ctx *Context, value SerializedValue) (reflect.Type, *refle
deserialize = kind_info.Deserialize deserialize = kind_info.Deserialize
} }
ctx.Log.Logf("serialize", "Deserializing: %d", ctx_type)
if value.Data == nil { if value.Data == nil {
reflect_type, _, value, err = deserialize(ctx, value) reflect_type, _, value, err = deserialize(ctx, value)
} else { } else {
@ -222,6 +226,6 @@ func DeserializeValue(ctx *Context, value SerializedValue) (reflect.Type, *refle
return nil, nil, value, err return nil, nil, value, err
} }
ctx.Log.Logf("serialize", "DeserializeValue: DONE %+v - %+v - %+v", value, reflect_type, reflect_value) ctx.Log.Logf("serialize", "Deserialized %+v - %+v - %+v - remaining %+v", reflect_type, reflect_value, err, value)
return reflect_type, reflect_value, value, nil return reflect_type, reflect_value, value, nil
} }

@ -27,6 +27,15 @@ func TestSerializeBasic(t *testing.T) {
testSerializeSliceSlice[[][]int](t, ctx, [][]int{{123, 456, 789, 101112}, {3253, 2341, 735, 212}, {123, 51}, nil}) testSerializeSliceSlice[[][]int](t, ctx, [][]int{{123, 456, 789, 101112}, {3253, 2341, 735, 212}, {123, 51}, nil})
testSerializeSliceSlice[[][]string](t, ctx, [][]string{{"123", "456", "789", "101112"}, {"3253", "2341", "735", "212"}, {"123", "51"}, nil}) testSerializeSliceSlice[[][]string](t, ctx, [][]string{{"123", "456", "789", "101112"}, {"3253", "2341", "735", "212"}, {"123", "51"}, nil})
testSerialize(t, ctx, []map[int8]map[*int8]string{})
testSerializeMap(t, ctx, map[int8]int32{
0: 1234,
2: 5678,
4: 9101,
6: 1121,
})
testSerialize(t, ctx, struct{ testSerialize(t, ctx, struct{
int `gv:"0"` int `gv:"0"`
string `gv:"1"` string `gv:"1"`
@ -82,7 +91,7 @@ func testSerializeComparable[T comparable](t *testing.T, ctx *Context, val T) {
} }
func testSerialize[T any](t *testing.T, ctx *Context, val T) T { func testSerialize[T any](t *testing.T, ctx *Context, val T) T {
value, err := SerializeValue(ctx, reflect.ValueOf(val)) value, err := SerializeAny(ctx, val)
fatalErr(t, err) fatalErr(t, err)
ctx.Log.Logf("test", "Serialized %+v to %+v", val, value) ctx.Log.Logf("test", "Serialized %+v to %+v", val, value)