diff --git a/context.go b/context.go index 27d003f..61158be 100644 --- a/context.go +++ b/context.go @@ -369,7 +369,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { return nil, err } - err = ctx.RegisterKind(reflect.String, reflect.TypeOf(""), StringType, nil, SerializeString, nil, DeserializeString) + err = ctx.RegisterKind(reflect.String, reflect.TypeOf(""), StringType, nil, SerializeString, nil, DeserializeString[string]) if err != nil { return nil, err } @@ -491,13 +491,13 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } node_id_type := reflect.TypeOf(RandID()) - err = ctx.RegisterType(node_id_type, NodeIDType, SerializeTypeStub, SerializeArray, DeserializeTypeStub[NodeID], DeserializeArray) + err = ctx.RegisterType(node_id_type, NodeIDType, SerializeTypeStub, SerializeUUID, DeserializeTypeStub[NodeID], DeserializeUUID[NodeID]) if err != nil { return nil, err } uuid_type := reflect.TypeOf(uuid.UUID{}) - err = ctx.RegisterType(uuid_type, UUIDType, SerializeTypeStub, SerializeArray, DeserializeTypeStub[uuid.UUID], DeserializeArray) + err = ctx.RegisterType(uuid_type, UUIDType, SerializeTypeStub, SerializeUUID, DeserializeTypeStub[uuid.UUID], DeserializeUUID[uuid.UUID]) if err != nil { return nil, err } diff --git a/event.go b/event.go index a0361fe..152bd54 100644 --- a/event.go +++ b/event.go @@ -6,9 +6,9 @@ import ( ) type EventExt struct { - Name string `"name"` - State string `"state"` - Parent *NodeID `"parent"` + Name string `gv:"name"` + State string `gv:"state"` + Parent *NodeID `gv:"parent"` } func NewEventExt(parent *NodeID, name string) *EventExt { @@ -91,19 +91,33 @@ func (ext *EventExt) Process(ctx *Context, node *Node, source NodeID, signal Sig messages = messages.Add(ctx, *ext.Parent, node, nil, signal) } + return messages, changes +} + +type TestEventExt struct {} + +func (ext *TestEventExt) Process(ctx *Context, node *Node, source NodeID, signal Signal) (Messages, Changes) { + var messages Messages = nil + var changes Changes = nil + switch sig := signal.(type) { case *EventControlSignal: - info, exists := transitions[sig.Command] - if exists == true { - if ext.State == info.from_state { - ext.State = info.to_state - messages = messages.Add(ctx, source, node, nil, NewSuccessSignal(sig.Id)) - node.QueueSignal(time.Now(), NewEventStateSignal(node.ID, ext.State, time.Now())) + event_ext, err := GetExt[*EventExt](node, EventExtType) + if err != nil { + messages = messages.Add(ctx, source, node, nil, NewErrorSignal(sig.Id, "not_event")) + } else { + info, exists := transitions[sig.Command] + if exists == true { + if event_ext.State == info.from_state { + event_ext.State = info.to_state + messages = messages.Add(ctx, source, node, nil, NewSuccessSignal(sig.Id)) + node.QueueSignal(time.Now(), NewEventStateSignal(node.ID, event_ext.State, time.Now())) + } else { + messages = messages.Add(ctx, source, node, nil, NewErrorSignal(sig.Id, "bad_state")) + } } else { - messages = messages.Add(ctx, source, node, nil, NewErrorSignal(sig.Id, "bad_state")) + messages = messages.Add(ctx, source, node, nil, NewErrorSignal(sig.Id, "bad_command")) } - } else { - messages = messages.Add(ctx, source, node, nil, NewErrorSignal(sig.Id, "bad_command")) } } diff --git a/gql_test.go b/gql_test.go index d3d9f35..fff7759 100644 --- a/gql_test.go +++ b/gql_test.go @@ -242,7 +242,7 @@ func TestGQLServer(t *testing.T) { } func TestGQLDB(t *testing.T) { - ctx := logTestContext(t, []string{"test", "serialize", "serialize_types", "deserialize_types", "node"}) + ctx := logTestContext(t, []string{"test", "node"}) TestUserNodeType := NewNodeType("TEST_USER") err := ctx.RegisterNodeType(TestUserNodeType, []ExtType{}) diff --git a/message.go b/message.go index f6466f7..7c87178 100644 --- a/message.go +++ b/message.go @@ -75,7 +75,7 @@ func NewMessage(ctx *Context, dest NodeID, source *Node, authorization *ClientAu return nil, err } - ser, err := signal_ser.MarshalBinary() + signal_chunks, err := signal_ser.Chunks() if err != nil { return nil, err } @@ -89,7 +89,7 @@ func NewMessage(ctx *Context, dest NodeID, source *Node, authorization *ClientAu return nil, err } sig_data := append(dest_ser, source_ser...) - sig_data = append(sig_data, ser...) + sig_data = append(sig_data, signal_chunks.Slice()...) var message_auth *Authorization = nil if authorization != nil { sig_data = append(sig_data, authorization.Signature...) diff --git a/node.go b/node.go index 654ba70..7ef758e 100644 --- a/node.go +++ b/node.go @@ -270,7 +270,7 @@ func nodeLoop(ctx *Context, node *Node) error { if err != nil { ctx.Log.Logf("signal", "SIGNAL_SERIALIZE_ERR: %s - %+v", err, msg.Signal) } - ser, err := signal_ser.MarshalBinary() + chunks, err := signal_ser.Chunks() if err != nil { ctx.Log.Logf("signal", "SIGNAL_SERIALIZE_ERR: %s - %+v", err, signal_ser) continue @@ -287,7 +287,7 @@ func nodeLoop(ctx *Context, node *Node) error { continue } sig_data := append(dst_id_ser, src_id_ser...) - sig_data = append(sig_data, ser...) + sig_data = append(sig_data, chunks.Slice()...) if msg.Authorization != nil { sig_data = append(sig_data, msg.Authorization.Signature...) } @@ -656,12 +656,12 @@ func WriteNode(ctx *Context, node *Node) error { if err != nil { return err } - bytes, err := node_serialized.MarshalBinary() + chunks, err := node_serialized.Chunks() if err != nil { return err } - ctx.Log.Logf("db_data", "DB_DATA: %+v", bytes) + ctx.Log.Logf("db_data", "DB_DATA: %+v", chunks.Slice()) id_bytes, err := node.ID.MarshalBinary() if err != nil { @@ -670,7 +670,7 @@ func WriteNode(ctx *Context, node *Node) error { ctx.Log.Logf("db", "DB_WRITE_ID: %+v", id_bytes) return ctx.DB.Update(func(txn *badger.Txn) error { - return txn.Set(id_bytes, bytes) + return txn.Set(id_bytes, chunks.Slice()) }) } diff --git a/serialize.go b/serialize.go index 58280e9..68cdecc 100644 --- a/serialize.go +++ b/serialize.go @@ -2,6 +2,7 @@ package graphvent import ( "crypto/sha512" + "encoding" "encoding/binary" "encoding/gob" "fmt" @@ -57,8 +58,118 @@ func (t PolicyType) String() string { return fmt.Sprintf("0x%x", uint64(t)) } +type Chunk struct { + Data []byte + Next *Chunk +} + +type Chunks struct { + First *Chunk + Last *Chunk +} + +func (chunks Chunks) String() string { + cur := chunks.First + str := fmt.Sprintf("Chunks(") + for cur != nil { + str = fmt.Sprintf("%s%+v, ", str, cur) + cur = cur.Next + } + + return fmt.Sprintf("%s)", str) +} + +func NewChunks(datas ...[]byte) Chunks { + var first *Chunk = nil + var last *Chunk = nil + + if len(datas) >= 1 { + first = &Chunk{ + Data: datas[0], + Next: nil, + } + last = first + + for _, data := range(datas[1:]) { + last.Next = &Chunk{ + Data: data, + Next: nil, + } + last = last.Next + } + } + + if (first == nil || last == nil) && (first != last) { + panic(fmt.Sprintf("Attempted to construct invalid Chunks with NewChunks %+v - %+v", first, last)) + } + return Chunks{ + First: first, + Last: last, + } +} + +func (chunks Chunks) AddDataToEnd(datas ...[]byte) Chunks { + if chunks.First == nil && chunks.Last == nil { + return NewChunks(datas...) + } else if chunks.First == nil || chunks.Last == nil { + panic(fmt.Sprintf("Invalid chunks %+v", chunks)) + } + + for _, data := range(datas) { + chunks.Last.Next = &Chunk{ + Data: data, + Next: nil, + } + chunks.Last = chunks.Last.Next + } + + return chunks +} + +func (chunks Chunks) AddChunksToEnd(new_chunks Chunks) Chunks { + if chunks.Last == nil && chunks.First == nil { + return new_chunks + } else if chunks.Last == nil || chunks.First == nil { + panic(fmt.Sprintf("Invalid chunks %+v", chunks)) + } else if new_chunks.Last == nil && new_chunks.First == nil { + return chunks + } else if new_chunks.Last == nil || new_chunks.First == nil { + panic(fmt.Sprintf("Invalid new_chunks %+v", new_chunks)) + } else { + chunks.Last.Next = new_chunks.First + chunks.Last = new_chunks.Last + return chunks + } +} + +func (chunks Chunks) GetSerializedSize() int { + total_size := 0 + cur := chunks.First + + for cur != nil { + total_size += len(cur.Data) + cur = cur.Next + } + return total_size +} + +func (chunks Chunks) Slice() []byte { + total_size := chunks.GetSerializedSize() + data := make([]byte, total_size) + data_ptr := 0 + + cur := chunks.First + for cur != nil { + copy(data[data_ptr:], cur.Data) + data_ptr += len(cur.Data) + cur = cur.Next + } + + return data +} + type TypeSerializeFn func(*Context, reflect.Type) ([]SerializedType, error) -type SerializeFn func(*Context, reflect.Value) ([]byte, error) +type SerializeFn func(*Context, reflect.Value) (Chunks, error) type TypeDeserializeFn func(*Context, []SerializedType) (reflect.Type, []SerializedType, error) type DeserializeFn func(*Context, reflect.Type, []byte) (reflect.Value, []byte, error) @@ -242,9 +353,9 @@ func GetStructInfo(ctx *Context, struct_type reflect.Type) (StructInfo, error) { }, nil } -func SerializeStruct(info StructInfo)func(*Context, reflect.Value)([]byte, error) { - return func(ctx *Context, value reflect.Value) ([]byte, error) { - data := make([]byte, 8) +func SerializeStruct(info StructInfo)func(*Context, reflect.Value)(Chunks, error) { + return func(ctx *Context, value reflect.Value) (Chunks, error) { + struct_chunks := Chunks{} for _, field_hash := range(info.FieldOrder) { field_hash_bytes := make([]byte, 8) binary.BigEndian.PutUint64(field_hash_bytes, uint64(field_hash)) @@ -252,16 +363,17 @@ func SerializeStruct(info StructInfo)func(*Context, reflect.Value)([]byte, error field_info := info.FieldMap[field_hash] field_value := value.FieldByIndex(field_info.Index) - field_serialized, err := SerializeValue(ctx, field_value) + field_chunks, err := SerializeValue(ctx, field_value) if err != nil { - return nil, err + return Chunks{}, err } - data = append(data, field_hash_bytes...) - data = append(data, field_serialized...) + struct_chunks = struct_chunks.AddDataToEnd(field_hash_bytes).AddChunksToEnd(field_chunks) + ctx.Log.Logf("serialize", "STRUCT_FIELD_CHUNKS: %+v", field_chunks) } - binary.BigEndian.PutUint64(data[0:8], uint64(len(info.FieldOrder))) - return data, nil + size_data := make([]byte, 8) + binary.BigEndian.PutUint64(size_data, uint64(len(info.FieldOrder))) + return NewChunks(size_data).AddChunksToEnd(struct_chunks), nil } } @@ -283,7 +395,7 @@ func DeserializeStruct(info StructInfo)func(*Context, reflect.Type, []byte)(refl field_hash := SerializedType(binary.BigEndian.Uint64(field_hash_bytes)) field_info, exists := info.FieldMap[field_hash] if exists == false { - return reflect.Value{}, nil, fmt.Errorf("0x%x is not a field in %+v", field_hash, info.Type) + return reflect.Value{}, nil, fmt.Errorf("%+v is not a field in %+v", field_hash, info.Type) } var field_value reflect.Value @@ -310,15 +422,15 @@ func DeserializeStruct(info StructInfo)func(*Context, reflect.Type, []byte)(refl } } -func SerializeGob(ctx *Context, value reflect.Value) ([]byte, error) { +func SerializeGob(ctx *Context, value reflect.Value) (Chunks, error) { data := make([]byte, 8) gob_ser, err := value.Interface().(gob.GobEncoder).GobEncode() if err != nil { - return nil, err + return Chunks{}, err } binary.BigEndian.PutUint64(data, uint64(len(gob_ser))) - return append(data, gob_ser...), nil + return NewChunks(data, gob_ser), nil } func DeserializeGob[T any, PT interface{gob.GobDecoder; *T}](ctx *Context, reflect_type reflect.Type, data []byte) (reflect.Value, []byte, error) { @@ -340,58 +452,58 @@ func DeserializeGob[T any, PT interface{gob.GobDecoder; *T}](ctx *Context, refle return gob_ptr.Elem(), data, nil } -func SerializeInt8(ctx *Context, value reflect.Value) ([]byte, error) { +func SerializeInt8(ctx *Context, value reflect.Value) (Chunks, error) { data := []byte{byte(value.Int())} - return data, nil + return NewChunks(data), nil } -func SerializeInt16(ctx *Context, value reflect.Value) ([]byte, error) { +func SerializeInt16(ctx *Context, value reflect.Value) (Chunks, error) { data := make([]byte, 2) binary.BigEndian.PutUint16(data, uint16(value.Int())) - return data, nil + return NewChunks(data), nil } -func SerializeInt32(ctx *Context, value reflect.Value) ([]byte, error) { +func SerializeInt32(ctx *Context, value reflect.Value) (Chunks, error) { data := make([]byte, 4) binary.BigEndian.PutUint32(data, uint32(value.Int())) - return data, nil + return NewChunks(data), nil } -func SerializeInt64(ctx *Context, value reflect.Value) ([]byte, error) { +func SerializeInt64(ctx *Context, value reflect.Value) (Chunks, error) { data := make([]byte, 8) binary.BigEndian.PutUint64(data, uint64(value.Int())) - return data, nil + return NewChunks(data), nil } -func SerializeUint8(ctx *Context, value reflect.Value) ([]byte, error) { +func SerializeUint8(ctx *Context, value reflect.Value) (Chunks, error) { data := []byte{byte(value.Uint())} - return data, nil + return NewChunks(data), nil } -func SerializeUint16(ctx *Context, value reflect.Value) ([]byte, error) { +func SerializeUint16(ctx *Context, value reflect.Value) (Chunks, error) { data := make([]byte, 2) binary.BigEndian.PutUint16(data, uint16(value.Uint())) - return data, nil + return NewChunks(data), nil } -func SerializeUint32(ctx *Context, value reflect.Value) ([]byte, error) { +func SerializeUint32(ctx *Context, value reflect.Value) (Chunks, error) { data := make([]byte, 4) binary.BigEndian.PutUint32(data, uint32(value.Uint())) - return data, nil + return NewChunks(data), nil } -func SerializeUint64(ctx *Context, value reflect.Value) ([]byte, error) { +func SerializeUint64(ctx *Context, value reflect.Value) (Chunks, error) { data := make([]byte, 8) binary.BigEndian.PutUint64(data, value.Uint()) - return data, nil + return NewChunks(data), nil } func DeserializeUint64[T ~uint64 | ~int64](ctx *Context, reflect_type reflect.Type, data []byte) (reflect.Value, []byte, error) { @@ -458,11 +570,11 @@ func DeserializeUint8[T ~uint8 | ~int8](ctx *Context, reflect_type reflect.Type, return uint_value, data, nil } -func SerializeFloat64(ctx *Context, value reflect.Value) ([]byte, error) { +func SerializeFloat64(ctx *Context, value reflect.Value) (Chunks, error) { data := make([]byte, 8) float_representation := math.Float64bits(value.Float()) binary.BigEndian.PutUint64(data, float_representation) - return data, nil + return NewChunks(data), nil } func DeserializeFloat64[T ~float64](ctx *Context, reflect_type reflect.Type, data []byte) (reflect.Value, []byte, error) { @@ -482,11 +594,11 @@ func DeserializeFloat64[T ~float64](ctx *Context, reflect_type reflect.Type, dat return float_value, data, nil } -func SerializeFloat32(ctx *Context, value reflect.Value) ([]byte, error) { +func SerializeFloat32(ctx *Context, value reflect.Value) (Chunks, error) { data := make([]byte, 4) float_representation := math.Float32bits(float32(value.Float())) binary.BigEndian.PutUint32(data, float_representation) - return data, nil + return NewChunks(data), nil } func DeserializeFloat32[T ~float32](ctx *Context, reflect_type reflect.Type, data []byte) (reflect.Value, []byte, error) { @@ -506,14 +618,14 @@ func DeserializeFloat32[T ~float32](ctx *Context, reflect_type reflect.Type, dat return float_value, data, nil } -func SerializeString(ctx *Context, value reflect.Value) ([]byte, error) { +func SerializeString(ctx *Context, value reflect.Value) (Chunks, error) { data := make([]byte, 8) binary.BigEndian.PutUint64(data, uint64(value.Len())) - return append(data, []byte(value.String())...), nil + return NewChunks(data, []byte(value.String())), nil } -func DeserializeString(ctx *Context, reflect_type reflect.Type, data []byte) (reflect.Value, []byte, error) { +func DeserializeString[T ~string](ctx *Context, reflect_type reflect.Type, data []byte) (reflect.Value, []byte, error) { if len(data) < 8 { return reflect.Value{}, nil, fmt.Errorf("Not enough data to deserialize string %d/8", len(data)) } @@ -527,17 +639,17 @@ func DeserializeString(ctx *Context, reflect_type reflect.Type, data []byte) (re } string_value := reflect.New(reflect_type).Elem() - string_value.Set(reflect.ValueOf(string(data[:size]))) + string_value.Set(reflect.ValueOf(T(string(data[:size])))) data = data[size:] return string_value, data, nil } -func SerializeBool(ctx *Context, value reflect.Value) ([]byte, error) { +func SerializeBool(ctx *Context, value reflect.Value) (Chunks, error) { if value.Bool() == true { - return []byte{0xFF}, nil + return NewChunks([]byte{0xFF}), nil } else { - return []byte{0x00}, nil + return NewChunks([]byte{0x00}), nil } } @@ -567,18 +679,18 @@ func DeserializeTypePointer(ctx *Context, type_stack []SerializedType) (reflect. return reflect.PointerTo(elem_type), remaining, nil } -func SerializePointer(ctx *Context, value reflect.Value) ([]byte, error) { +func SerializePointer(ctx *Context, value reflect.Value) (Chunks, error) { if value.IsZero() { - return []byte{0x00}, nil + return NewChunks([]byte{0x00}), nil } else { - flags := []byte{0x01} + flags := NewChunks([]byte{0x01}) - elem_data, err := SerializeValue(ctx, value.Elem()) + elem_chunks, err := SerializeValue(ctx, value.Elem()) if err != nil { - return nil, err + return Chunks{}, err } - return append(flags, elem_data...), nil + return flags.AddChunksToEnd(elem_chunks), nil } } @@ -619,25 +731,26 @@ func SerializeTypeElem(ctx *Context, reflect_type reflect.Type) ([]SerializedTyp return SerializeType(ctx, reflect_type.Elem()) } -func SerializeSlice(ctx *Context, value reflect.Value) ([]byte, error) { +func SerializeSlice(ctx *Context, value reflect.Value) (Chunks, error) { if value.IsZero() { - return []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, nil + return NewChunks([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}), nil } else if value.Len() == 0 { - return []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, nil + return NewChunks([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), nil } else { - data := make([]byte, 8) - binary.BigEndian.PutUint64(data, uint64(value.Len())) - + slice_chunks := Chunks{} for i := 0; i < value.Len(); i += 1 { val := value.Index(i) - element, err := SerializeValue(ctx, val) + element_chunks, err := SerializeValue(ctx, val) if err != nil { - return nil, err + return Chunks{}, err } - data = append(data, element...) + slice_chunks = slice_chunks.AddChunksToEnd(element_chunks) } - return data, nil + size_data := make([]byte, 8) + binary.BigEndian.PutUint64(size_data, uint64(value.Len())) + + return NewChunks(size_data).AddChunksToEnd(slice_chunks), nil } } @@ -708,12 +821,12 @@ func DeserializeTypeMap(ctx *Context, type_stack []SerializedType) (reflect.Type return map_type, after_elem, nil } -func SerializeMap(ctx *Context, value reflect.Value) ([]byte, error) { +func SerializeMap(ctx *Context, value reflect.Value) (Chunks, error) { if value.IsZero() == true { - return []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, nil + return NewChunks([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}), nil } - map_data := []byte{} + map_chunks := Chunks{} map_size := uint64(0) map_iter := value.MapRange() for map_iter.Next() { @@ -721,23 +834,23 @@ func SerializeMap(ctx *Context, value reflect.Value) ([]byte, error) { key := map_iter.Key() val := map_iter.Value() - key_data, err := SerializeValue(ctx, key) + key_chunks, err := SerializeValue(ctx, key) if err != nil { - return nil, err + return Chunks{}, err } - map_data = append(map_data, key_data...) + map_chunks = map_chunks.AddChunksToEnd(key_chunks) - val_data, err := SerializeValue(ctx, val) + val_chunks, err := SerializeValue(ctx, val) if err != nil { - return nil, err + return Chunks{}, err } - map_data = append(map_data, val_data...) + map_chunks = map_chunks.AddChunksToEnd(val_chunks) } size_data := make([]byte, 8) binary.BigEndian.PutUint64(size_data, map_size) - return append(size_data, map_data...), nil + return NewChunks(size_data).AddChunksToEnd(map_chunks), nil } func DeserializeMap(ctx *Context, reflect_type reflect.Type, data []byte) (reflect.Value, []byte, error) { @@ -788,15 +901,42 @@ func SerializeTypeArray(ctx *Context, reflect_type reflect.Type) ([]SerializedTy return append([]SerializedType{size}, elem_stack...), nil } -func SerializeArray(ctx *Context, value reflect.Value) ([]byte, error) { - data := []byte{} +func SerializeUUID(ctx *Context, value reflect.Value) (Chunks, error) { + uuid_ser, err := value.Interface().(encoding.BinaryMarshaler).MarshalBinary() + if err != nil { + return Chunks{}, err + } + + if len(uuid_ser) != 16 { + return Chunks{}, fmt.Errorf("Wrong length of uuid: %d/16", len(uuid_ser)) + } + + return NewChunks(uuid_ser), nil +} + +func DeserializeUUID[T ~[16]byte](ctx *Context, reflect_type reflect.Type, data []byte) (reflect.Value, []byte, error) { + if len(data) < 16 { + return reflect.Value{}, nil, fmt.Errorf("Not enough data to deserialize UUID %d/16", len(data)) + } + + uuid_bytes := data[:16] + data = data[16:] + + uuid_value := reflect.New(reflect_type).Elem() + uuid_value.Set(reflect.ValueOf(T(uuid_bytes))) + + return uuid_value, data, nil +} + +func SerializeArray(ctx *Context, value reflect.Value) (Chunks, error) { + data := Chunks{} for i := 0; i < value.Len(); i += 1 { element := value.Index(i) - element_data, err := SerializeValue(ctx, element) + element_chunks, err := SerializeValue(ctx, element) if err != nil { - return nil, err + return Chunks{}, err } - data = append(data, element_data...) + data = data.AddChunksToEnd(element_chunks) } return data, nil @@ -834,27 +974,29 @@ func DeserializeArray(ctx *Context, reflect_type reflect.Type, data []byte) (ref return array_value, data, nil } -func SerializeInterface(ctx *Context, value reflect.Value) ([]byte, error) { +func SerializeInterface(ctx *Context, value reflect.Value) (Chunks, error) { if value.IsZero() == true { - return []byte{0xFF}, nil + return NewChunks([]byte{0xFF}), nil } type_stack, err := SerializeType(ctx, value.Elem().Type()) if err != nil { - return nil, err + return Chunks{}, err } - data, err := SerializeValue(ctx, value.Elem()) + elem_chunks, err := SerializeValue(ctx, value.Elem()) if err != nil { - return nil, err + return Chunks{}, err } - serialized_value, err := SerializedValue{type_stack, data}.MarshalBinary() + data := elem_chunks.Slice() + + serialized_chunks, err := SerializedValue{type_stack, data}.Chunks() if err != nil { - return nil, err + return Chunks{}, err } - return append([]byte{0x00}, serialized_value...), nil + return NewChunks([]byte{0x00}).AddChunksToEnd(serialized_chunks), nil } func DeserializeInterface(ctx *Context, reflect_type reflect.Type, data []byte) (reflect.Value, []byte, error) { @@ -904,7 +1046,8 @@ func SerializeAny[T any](ctx *Context, value T) (SerializedValue, error) { if err != nil { return SerializedValue{}, err } - return SerializedValue{type_stack, data}, nil + + return SerializedValue{type_stack, data.Slice()}, nil } func SerializeType(ctx *Context, reflect_type reflect.Type) ([]SerializedType, error) { @@ -940,9 +1083,7 @@ func SerializeType(ctx *Context, reflect_type reflect.Type) ([]SerializedType, e } } -func SerializeValue(ctx *Context, value reflect.Value) ([]byte, error) { - ctx.Log.Logf("serialize", "Serializing value %+v", value) - +func SerializeValue(ctx *Context, value reflect.Value) (Chunks, error) { type_info, type_exists := ctx.TypeReflects[value.Type()] var serialize SerializeFn = nil if type_exists == true { @@ -956,7 +1097,7 @@ func SerializeValue(ctx *Context, value reflect.Value) ([]byte, error) { if handled { serialize = kind_info.Serialize } else { - return nil, fmt.Errorf("Don't know how to serialize %+v", value.Type()) + return Chunks{}, fmt.Errorf("Don't know how to serialize %+v", value.Type()) } } @@ -992,25 +1133,21 @@ func SerializeField(ctx *Context, ext Extension, field_name string) (SerializedV if err != nil { return SerializedValue{}, err } - return SerializedValue{type_stack, data}, nil + return SerializedValue{type_stack, data.Slice()}, nil } -func (value SerializedValue) MarshalBinary() ([]byte, error) { - data := make([]byte, value.SerializedSize()) - binary.BigEndian.PutUint64(data[0:8], uint64(len(value.TypeStack))) - binary.BigEndian.PutUint64(data[8:16], uint64(len(value.Data))) +func (value SerializedValue) Chunks() (Chunks, error) { + header_data := make([]byte, 16) + binary.BigEndian.PutUint64(header_data[0:8], uint64(len(value.TypeStack))) + binary.BigEndian.PutUint64(header_data[8:16], uint64(len(value.Data))) - for i, t := range value.TypeStack { - type_start := (i + 2) * 8 - type_end := (i + 3) * 8 - binary.BigEndian.PutUint64(data[type_start:type_end], uint64(t)) + type_stack_bytes := make([][]byte, len(value.TypeStack)) + for i, ctx_type := range(value.TypeStack) { + type_stack_bytes[i] = make([]byte, 8) + binary.BigEndian.PutUint64(type_stack_bytes[i], uint64(ctx_type)) } - return append(data, value.Data...), nil -} - -func (value SerializedValue) SerializedSize() uint64 { - return uint64((len(value.TypeStack) + 2) * 8) + return NewChunks(header_data).AddDataToEnd(type_stack_bytes...).AddDataToEnd(value.Data), nil } func ParseSerializedValue(data []byte) (SerializedValue, []byte, error) { diff --git a/serialize_test.go b/serialize_test.go index a78d744..ed02eaa 100644 --- a/serialize_test.go +++ b/serialize_test.go @@ -13,7 +13,6 @@ func TestSerializeTest(t *testing.T) { testSerialize(t, ctx, map[NodeID]ReqInfo{ RandID(): {}, RandID(): {}, - RandID(): {}, }) } @@ -220,16 +219,16 @@ func testSerializeComparable[T comparable](t *testing.T, ctx *Context, val T) { func testSerialize[T any](t *testing.T, ctx *Context, val T) T { value := reflect.ValueOf(&val).Elem() type_stack, err := SerializeType(ctx, value.Type()) - data, err := SerializeValue(ctx, value) - value_serialized := SerializedValue{type_stack, data} + chunks, err := SerializeValue(ctx, value) + value_serialized := SerializedValue{type_stack, chunks.Slice()} fatalErr(t, err) - ctx.Log.Logf("test", "Serialized %+v to %+v", val, value_serialized) + ctx.Log.Logf("test", "Serialized %+v to %+v(%d)", val, value_serialized, len(value_serialized.Data)) - ser, err := value_serialized.MarshalBinary() + value_chunks, err := value_serialized.Chunks() fatalErr(t, err) - ctx.Log.Logf("test", "Binary: %+v", ser) + ctx.Log.Logf("test", "Binary: %+v", value_chunks.Slice()) - val_parsed, remaining_parse, err := ParseSerializedValue(ser) + val_parsed, remaining_parse, err := ParseSerializedValue(value_chunks.Slice()) fatalErr(t, err) ctx.Log.Logf("test", "Parsed: %+v", val_parsed)