1235 lines
36 KiB
Go
1235 lines
36 KiB
Go
package graphvent
|
|
|
|
import (
|
|
"crypto/sha512"
|
|
"encoding"
|
|
"encoding/binary"
|
|
"encoding/gob"
|
|
"fmt"
|
|
"math"
|
|
"reflect"
|
|
"sort"
|
|
"bytes"
|
|
)
|
|
|
|
const (
|
|
TagBase = "GraphventTag"
|
|
ExtTypeBase = "ExtType"
|
|
NodeTypeBase = "NodeType"
|
|
SignalTypeBase = "SignalType"
|
|
PolicyTypeBase = "PolicyType"
|
|
SerializedTypeBase = "SerializedType"
|
|
FieldNameBase = "FieldName"
|
|
)
|
|
|
|
func Hash(base string, name string) SerializedType {
|
|
digest := append([]byte(base), 0x00)
|
|
digest = append(digest, []byte(name)...)
|
|
hash := sha512.Sum512(digest)
|
|
return SerializedType(binary.BigEndian.Uint64(hash[0:8]))
|
|
}
|
|
|
|
type SerializedType uint64
|
|
|
|
func (t SerializedType) String() string {
|
|
return fmt.Sprintf("0x%x", uint64(t))
|
|
}
|
|
|
|
type ExtType SerializedType
|
|
|
|
func (t ExtType) String() string {
|
|
return fmt.Sprintf("0x%x", uint64(t))
|
|
}
|
|
|
|
type NodeType SerializedType
|
|
|
|
func (t NodeType) String() string {
|
|
return fmt.Sprintf("0x%x", uint64(t))
|
|
}
|
|
|
|
type SignalType SerializedType
|
|
|
|
func (t SignalType) String() string {
|
|
return fmt.Sprintf("0x%x", uint64(t))
|
|
}
|
|
|
|
type PolicyType SerializedType
|
|
|
|
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) (Chunks, error)
|
|
type TypeDeserializeFn func(*Context, []SerializedType) (reflect.Type, []SerializedType, error)
|
|
type DeserializeFn func(*Context, reflect.Type, []byte) (reflect.Value, []byte, error)
|
|
|
|
func NewExtType(name string) ExtType {
|
|
return ExtType(Hash(ExtTypeBase, name))
|
|
}
|
|
|
|
func NewNodeType(name string) NodeType {
|
|
return NodeType(Hash(NodeTypeBase, name))
|
|
}
|
|
|
|
func NewSignalType(name string) SignalType {
|
|
return SignalType(Hash(SignalTypeBase, name))
|
|
}
|
|
|
|
func NewPolicyType(name string) PolicyType {
|
|
return PolicyType(Hash(PolicyTypeBase, name))
|
|
}
|
|
|
|
func NewSerializedType(name string) SerializedType {
|
|
return Hash(SerializedTypeBase, name)
|
|
}
|
|
|
|
var (
|
|
ListenerExtType = NewExtType("LISTENER")
|
|
LockableExtType = NewExtType("LOCKABLE")
|
|
GQLExtType = NewExtType("GQL")
|
|
GroupExtType = NewExtType("GROUP")
|
|
ACLExtType = NewExtType("ACL")
|
|
EventExtType = NewExtType("EVENT")
|
|
|
|
GQLNodeType = NewNodeType("GQL")
|
|
BaseNodeType = NewNodeType("BASE")
|
|
GroupNodeType = NewNodeType("GROUP")
|
|
|
|
StopSignalType = NewSignalType("STOP")
|
|
CreateSignalType = NewSignalType("CREATE")
|
|
StartSignalType = NewSignalType("START")
|
|
StatusSignalType = NewSignalType("STATUS")
|
|
LinkSignalType = NewSignalType("LINK")
|
|
LockSignalType = NewSignalType("LOCK")
|
|
TimeoutSignalType = NewSignalType("TIMEOUT")
|
|
ReadSignalType = NewSignalType("READ")
|
|
ACLTimeoutSignalType = NewSignalType("ACL_TIMEOUT")
|
|
ErrorSignalType = NewSignalType("ERROR")
|
|
SuccessSignalType = NewSignalType("SUCCESS")
|
|
ReadResultSignalType = NewSignalType("READ_RESULT")
|
|
RemoveMemberSignalType = NewSignalType("REMOVE_MEMBER")
|
|
AddMemberSignalType = NewSignalType("ADD_MEMBER")
|
|
ACLSignalType = NewSignalType("ACL")
|
|
AddSubGroupSignalType = NewSignalType("ADD_SUBGROUP")
|
|
RemoveSubGroupSignalType = NewSignalType("REMOVE_SUBGROUP")
|
|
StoppedSignalType = NewSignalType("STOPPED")
|
|
EventControlSignalType = NewSignalType("EVENT_CONTORL")
|
|
EventStateSignalType = NewSignalType("VEX_MATCH_STATUS")
|
|
|
|
MemberOfPolicyType = NewPolicyType("USER_OF")
|
|
RequirementOfPolicyType = NewPolicyType("REQUIEMENT_OF")
|
|
PerNodePolicyType = NewPolicyType("PER_NODE")
|
|
AllNodesPolicyType = NewPolicyType("ALL_NODES")
|
|
ACLProxyPolicyType = NewPolicyType("ACL_PROXY")
|
|
|
|
ErrorType = NewSerializedType("ERROR")
|
|
PointerType = NewSerializedType("POINTER")
|
|
SliceType = NewSerializedType("SLICE")
|
|
StructType = NewSerializedType("STRUCT")
|
|
IntType = NewSerializedType("INT")
|
|
UIntType = NewSerializedType("UINT")
|
|
BoolType = NewSerializedType("BOOL")
|
|
Float64Type = NewSerializedType("FLOAT64")
|
|
Float32Type = NewSerializedType("FLOAT32")
|
|
UInt8Type = NewSerializedType("UINT8")
|
|
UInt16Type = NewSerializedType("UINT16")
|
|
UInt32Type = NewSerializedType("UINT32")
|
|
UInt64Type = NewSerializedType("UINT64")
|
|
Int8Type = NewSerializedType("INT8")
|
|
Int16Type = NewSerializedType("INT16")
|
|
Int32Type = NewSerializedType("INT32")
|
|
Int64Type = NewSerializedType("INT64")
|
|
StringType = NewSerializedType("STRING")
|
|
ArrayType = NewSerializedType("ARRAY")
|
|
InterfaceType = NewSerializedType("INTERFACE")
|
|
MapType = NewSerializedType("MAP")
|
|
|
|
ReqStateType = NewSerializedType("REQ_STATE")
|
|
WaitInfoType = NewSerializedType("WAIT_INFO")
|
|
SignalDirectionType = NewSerializedType("SIGNAL_DIRECTION")
|
|
NodeStructType = NewSerializedType("NODE_STRUCT")
|
|
QueuedSignalType = NewSerializedType("QUEUED_SIGNAL")
|
|
NodeTypeSerialized = NewSerializedType("NODE_TYPE")
|
|
ChangesSerialized = NewSerializedType("CHANGES")
|
|
ExtTypeSerialized = NewSerializedType("EXT_TYPE")
|
|
PolicyTypeSerialized = NewSerializedType("POLICY_TYPE")
|
|
ExtSerialized = NewSerializedType("EXTENSION")
|
|
PolicySerialized = NewSerializedType("POLICY")
|
|
SignalSerialized = NewSerializedType("SIGNAL")
|
|
NodeIDType = NewSerializedType("NODE_ID")
|
|
UUIDType = NewSerializedType("UUID")
|
|
PendingACLType = NewSerializedType("PENDING_ACL")
|
|
PendingSignalType = NewSerializedType("PENDING_SIGNAL")
|
|
TimeType = NewSerializedType("TIME")
|
|
DurationType = NewSerializedType("DURATION")
|
|
ResponseType = NewSerializedType("RESPONSE")
|
|
StatusType = NewSerializedType("STATUS")
|
|
TreeType = NewSerializedType("TREE")
|
|
SerializedTypeSerialized = NewSerializedType("SERIALIZED_TYPE")
|
|
)
|
|
|
|
type FieldInfo struct {
|
|
Index []int
|
|
TypeStack []SerializedType
|
|
Type reflect.Type
|
|
}
|
|
|
|
type StructInfo struct {
|
|
Type reflect.Type
|
|
FieldOrder []SerializedType
|
|
FieldMap map[SerializedType]FieldInfo
|
|
PostDeserialize bool
|
|
PostDeserializeIdx int
|
|
}
|
|
|
|
type Deserializable interface {
|
|
PostDeserialize(*Context) error
|
|
}
|
|
|
|
var deserializable_zero Deserializable = nil
|
|
var DeserializableType = reflect.TypeOf(&deserializable_zero).Elem()
|
|
|
|
func GetStructInfo(ctx *Context, struct_type reflect.Type) (StructInfo, error) {
|
|
field_order := []SerializedType{}
|
|
field_map := map[SerializedType]FieldInfo{}
|
|
for _, field := range reflect.VisibleFields(struct_type) {
|
|
gv_tag, tagged_gv := field.Tag.Lookup("gv")
|
|
if tagged_gv == false {
|
|
continue
|
|
} else {
|
|
field_hash := Hash(FieldNameBase, gv_tag)
|
|
_, exists := field_map[field_hash]
|
|
if exists == true {
|
|
return StructInfo{}, fmt.Errorf("gv tag %s is repeated", gv_tag)
|
|
} else {
|
|
field_type_stack, err := SerializeType(ctx, field.Type)
|
|
if err != nil {
|
|
return StructInfo{}, err
|
|
}
|
|
field_map[field_hash] = FieldInfo{
|
|
field.Index,
|
|
field_type_stack,
|
|
field.Type,
|
|
}
|
|
field_order = append(field_order, field_hash)
|
|
}
|
|
}
|
|
}
|
|
|
|
sort.Slice(field_order, func(i, j int) bool {
|
|
return uint64(field_order[i]) < uint64(field_order[j])
|
|
})
|
|
|
|
post_deserialize := false
|
|
post_deserialize_idx := 0
|
|
ptr_type := reflect.PointerTo(struct_type)
|
|
if ptr_type.Implements(DeserializableType) {
|
|
post_deserialize = true
|
|
for i := 0; i < ptr_type.NumMethod(); i += 1 {
|
|
method := ptr_type.Method(i)
|
|
if method.Name == "PostDeserialize" {
|
|
post_deserialize_idx = i
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
return StructInfo{
|
|
struct_type,
|
|
field_order,
|
|
field_map,
|
|
post_deserialize,
|
|
post_deserialize_idx,
|
|
}, nil
|
|
}
|
|
|
|
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))
|
|
|
|
field_info := info.FieldMap[field_hash]
|
|
field_value := value.FieldByIndex(field_info.Index)
|
|
|
|
field_chunks, err := SerializeValue(ctx, field_value)
|
|
if err != nil {
|
|
return Chunks{}, err
|
|
}
|
|
|
|
struct_chunks = struct_chunks.AddDataToEnd(field_hash_bytes).AddChunksToEnd(field_chunks)
|
|
ctx.Log.Logf("serialize", "STRUCT_FIELD_CHUNKS: %+v", field_chunks)
|
|
}
|
|
size_data := make([]byte, 8)
|
|
binary.BigEndian.PutUint64(size_data, uint64(len(info.FieldOrder)))
|
|
return NewChunks(size_data).AddChunksToEnd(struct_chunks), nil
|
|
}
|
|
}
|
|
|
|
func DeserializeStruct(info StructInfo)func(*Context, reflect.Type, []byte)(reflect.Value, []byte, error) {
|
|
return func(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 struct %d/8", len(data))
|
|
}
|
|
|
|
num_field_bytes := data[:8]
|
|
data = data[8:]
|
|
|
|
num_fields := binary.BigEndian.Uint64(num_field_bytes)
|
|
|
|
struct_value := reflect.New(reflect_type).Elem()
|
|
for i := uint64(0); i < num_fields; i ++ {
|
|
field_hash_bytes := data[:8]
|
|
data = data[8:]
|
|
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("%+v is not a field in %+v", field_hash, info.Type)
|
|
}
|
|
|
|
var field_value reflect.Value
|
|
var err error
|
|
field_value, data, err = DeserializeValue(ctx, field_info.Type, data)
|
|
if err != nil {
|
|
return reflect.Value{}, nil, err
|
|
}
|
|
|
|
field_reflect := struct_value.FieldByIndex(field_info.Index)
|
|
field_reflect.Set(field_value)
|
|
}
|
|
|
|
if info.PostDeserialize == true {
|
|
post_deserialize_method := struct_value.Addr().Method(info.PostDeserializeIdx)
|
|
results := post_deserialize_method.Call([]reflect.Value{reflect.ValueOf(ctx)})
|
|
err_if := results[0].Interface()
|
|
if err_if != nil {
|
|
return reflect.Value{}, nil, err_if.(error)
|
|
}
|
|
}
|
|
|
|
return struct_value, data, nil
|
|
}
|
|
}
|
|
|
|
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 Chunks{}, err
|
|
}
|
|
|
|
binary.BigEndian.PutUint64(data, uint64(len(gob_ser)))
|
|
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) {
|
|
if len(data) < 8 {
|
|
return reflect.Value{}, nil, fmt.Errorf("Not enough bytes to deserialize gob %d/8", len(data))
|
|
}
|
|
|
|
size_bytes := data[:8]
|
|
size := binary.BigEndian.Uint64(size_bytes)
|
|
gob_data := data[8:8+size]
|
|
data = data[8+size:]
|
|
|
|
gob_ptr := reflect.New(reflect_type)
|
|
err := gob_ptr.Interface().(gob.GobDecoder).GobDecode(gob_data)
|
|
if err != nil {
|
|
return reflect.Value{}, nil, err
|
|
}
|
|
|
|
return gob_ptr.Elem(), data, nil
|
|
}
|
|
|
|
func SerializeInt8(ctx *Context, value reflect.Value) (Chunks, error) {
|
|
data := []byte{byte(value.Int())}
|
|
|
|
return NewChunks(data), nil
|
|
}
|
|
|
|
func SerializeInt16(ctx *Context, value reflect.Value) (Chunks, error) {
|
|
data := make([]byte, 2)
|
|
binary.BigEndian.PutUint16(data, uint16(value.Int()))
|
|
|
|
return NewChunks(data), nil
|
|
}
|
|
|
|
func SerializeInt32(ctx *Context, value reflect.Value) (Chunks, error) {
|
|
data := make([]byte, 4)
|
|
binary.BigEndian.PutUint32(data, uint32(value.Int()))
|
|
|
|
return NewChunks(data), nil
|
|
}
|
|
|
|
func SerializeInt64(ctx *Context, value reflect.Value) (Chunks, error) {
|
|
data := make([]byte, 8)
|
|
binary.BigEndian.PutUint64(data, uint64(value.Int()))
|
|
|
|
return NewChunks(data), nil
|
|
}
|
|
|
|
func SerializeUint8(ctx *Context, value reflect.Value) (Chunks, error) {
|
|
data := []byte{byte(value.Uint())}
|
|
|
|
return NewChunks(data), nil
|
|
}
|
|
|
|
func SerializeUint16(ctx *Context, value reflect.Value) (Chunks, error) {
|
|
data := make([]byte, 2)
|
|
binary.BigEndian.PutUint16(data, uint16(value.Uint()))
|
|
|
|
return NewChunks(data), nil
|
|
}
|
|
|
|
func SerializeUint32(ctx *Context, value reflect.Value) (Chunks, error) {
|
|
data := make([]byte, 4)
|
|
binary.BigEndian.PutUint32(data, uint32(value.Uint()))
|
|
|
|
return NewChunks(data), nil
|
|
}
|
|
|
|
func SerializeUint64(ctx *Context, value reflect.Value) (Chunks, error) {
|
|
data := make([]byte, 8)
|
|
binary.BigEndian.PutUint64(data, value.Uint())
|
|
|
|
return NewChunks(data), nil
|
|
}
|
|
|
|
func DeserializeUint64[T ~uint64 | ~int64](ctx *Context, reflect_type reflect.Type, data []byte) (reflect.Value, []byte, error) {
|
|
uint_size := 8
|
|
if len(data) < uint_size {
|
|
return reflect.Value{}, nil, fmt.Errorf("Not enough data to deserialize uint %d/%d", len(data), uint_size)
|
|
}
|
|
|
|
uint_bytes := data[:uint_size]
|
|
data = data[uint_size:]
|
|
uint_value := reflect.New(reflect_type).Elem()
|
|
|
|
typed_value := T(binary.BigEndian.Uint64(uint_bytes))
|
|
uint_value.Set(reflect.ValueOf(typed_value))
|
|
|
|
return uint_value, data, nil
|
|
}
|
|
|
|
func DeserializeUint32[T ~uint32 | ~uint | ~int32 | ~int](ctx *Context, reflect_type reflect.Type, data []byte) (reflect.Value, []byte, error) {
|
|
uint_size := 4
|
|
if len(data) < uint_size {
|
|
return reflect.Value{}, nil, fmt.Errorf("Not enough data to deserialize uint %d/%d", len(data), uint_size)
|
|
}
|
|
|
|
uint_bytes := data[:uint_size]
|
|
data = data[uint_size:]
|
|
uint_value := reflect.New(reflect_type).Elem()
|
|
|
|
typed_value := T(binary.BigEndian.Uint32(uint_bytes))
|
|
uint_value.Set(reflect.ValueOf(typed_value))
|
|
|
|
return uint_value, data, nil
|
|
}
|
|
|
|
func DeserializeUint16[T ~uint16 | ~int16](ctx *Context, reflect_type reflect.Type, data []byte) (reflect.Value, []byte, error) {
|
|
uint_size := 2
|
|
if len(data) < uint_size {
|
|
return reflect.Value{}, nil, fmt.Errorf("Not enough data to deserialize uint %d/%d", len(data), uint_size)
|
|
}
|
|
|
|
uint_bytes := data[:uint_size]
|
|
data = data[uint_size:]
|
|
uint_value := reflect.New(reflect_type).Elem()
|
|
|
|
typed_value := T(binary.BigEndian.Uint16(uint_bytes))
|
|
uint_value.Set(reflect.ValueOf(typed_value))
|
|
|
|
return uint_value, data, nil
|
|
}
|
|
|
|
func DeserializeUint8[T ~uint8 | ~int8](ctx *Context, reflect_type reflect.Type, data []byte) (reflect.Value, []byte, error) {
|
|
uint_size := 1
|
|
if len(data) < uint_size {
|
|
return reflect.Value{}, nil, fmt.Errorf("Not enough data to deserialize uint %d/%d", len(data), uint_size)
|
|
}
|
|
|
|
uint_bytes := data[:uint_size]
|
|
data = data[uint_size:]
|
|
uint_value := reflect.New(reflect_type).Elem()
|
|
|
|
typed_value := T(uint_bytes[0])
|
|
uint_value.Set(reflect.ValueOf(typed_value))
|
|
|
|
return uint_value, data, nil
|
|
}
|
|
|
|
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 NewChunks(data), nil
|
|
}
|
|
|
|
func DeserializeFloat64[T ~float64](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 float64 %d/8", len(data))
|
|
}
|
|
|
|
float_bytes := data[0:8]
|
|
data = data[8:]
|
|
|
|
float_representation := binary.BigEndian.Uint64(float_bytes)
|
|
float := math.Float64frombits(float_representation)
|
|
|
|
float_value := reflect.New(reflect_type).Elem()
|
|
float_value.Set(reflect.ValueOf(T(float)))
|
|
|
|
return float_value, data, nil
|
|
}
|
|
|
|
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 NewChunks(data), nil
|
|
}
|
|
|
|
func DeserializeFloat32[T ~float32](ctx *Context, reflect_type reflect.Type, data []byte) (reflect.Value, []byte, error) {
|
|
if len(data) < 4 {
|
|
return reflect.Value{}, nil, fmt.Errorf("Not enough data to deserialize float32 %d/4", len(data))
|
|
}
|
|
|
|
float_bytes := data[0:4]
|
|
data = data[4:]
|
|
|
|
float_representation := binary.BigEndian.Uint32(float_bytes)
|
|
float := math.Float32frombits(float_representation)
|
|
|
|
float_value := reflect.New(reflect_type).Elem()
|
|
float_value.Set(reflect.ValueOf(T(float)))
|
|
|
|
return float_value, data, nil
|
|
}
|
|
|
|
func SerializeString(ctx *Context, value reflect.Value) (Chunks, error) {
|
|
data := make([]byte, 8)
|
|
binary.BigEndian.PutUint64(data, uint64(value.Len()))
|
|
|
|
return NewChunks(data, []byte(value.String())), nil
|
|
}
|
|
|
|
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))
|
|
}
|
|
|
|
size_bytes := data[0:8]
|
|
data = data[8:]
|
|
|
|
size := binary.BigEndian.Uint64(size_bytes)
|
|
if len(data) < int(size) {
|
|
return reflect.Value{}, nil, fmt.Errorf("Not enough data to deserialize string of len %d, %d/%d", size, len(data), size)
|
|
}
|
|
|
|
string_value := reflect.New(reflect_type).Elem()
|
|
string_value.Set(reflect.ValueOf(T(string(data[:size]))))
|
|
data = data[size:]
|
|
|
|
return string_value, data, nil
|
|
}
|
|
|
|
func SerializeBool(ctx *Context, value reflect.Value) (Chunks, error) {
|
|
if value.Bool() == true {
|
|
return NewChunks([]byte{0xFF}), nil
|
|
} else {
|
|
return NewChunks([]byte{0x00}), nil
|
|
}
|
|
}
|
|
|
|
func DeserializeBool[T ~bool](ctx *Context, reflect_type reflect.Type, data []byte) (reflect.Value, []byte, error) {
|
|
if len(data) < 1 {
|
|
return reflect.Value{}, nil, fmt.Errorf("Not enough data to deserialize bool %d/1", len(data))
|
|
}
|
|
byte := data[0]
|
|
data = data[1:]
|
|
|
|
bool_value := reflect.New(reflect_type).Elem()
|
|
if byte == 0x00 {
|
|
bool_value.Set(reflect.ValueOf(T(false)))
|
|
} else {
|
|
bool_value.Set(reflect.ValueOf(T(true)))
|
|
}
|
|
|
|
return bool_value, data, nil
|
|
}
|
|
|
|
func DeserializeTypePointer(ctx *Context, type_stack []SerializedType) (reflect.Type, []SerializedType, error) {
|
|
elem_type, remaining, err := DeserializeType(ctx, type_stack)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return reflect.PointerTo(elem_type), remaining, nil
|
|
}
|
|
|
|
func SerializePointer(ctx *Context, value reflect.Value) (Chunks, error) {
|
|
if value.IsZero() {
|
|
return NewChunks([]byte{0x00}), nil
|
|
} else {
|
|
flags := NewChunks([]byte{0x01})
|
|
|
|
elem_chunks, err := SerializeValue(ctx, value.Elem())
|
|
if err != nil {
|
|
return Chunks{}, err
|
|
}
|
|
|
|
return flags.AddChunksToEnd(elem_chunks), nil
|
|
}
|
|
}
|
|
|
|
func DeserializePointer(ctx *Context, reflect_type reflect.Type, data []byte) (reflect.Value, []byte, error) {
|
|
if len(data) < 1 {
|
|
return reflect.Value{}, nil, fmt.Errorf("Not enough data to deserialize pointer %d/1", len(data))
|
|
}
|
|
|
|
flags := data[0]
|
|
data = data[1:]
|
|
|
|
pointer_value := reflect.New(reflect_type).Elem()
|
|
|
|
if flags != 0x00 {
|
|
var element_value reflect.Value
|
|
var err error
|
|
element_value, data, err = DeserializeValue(ctx, reflect_type.Elem(), data)
|
|
if err != nil {
|
|
return reflect.Value{}, nil, err
|
|
}
|
|
|
|
pointer_value.Set(element_value.Addr())
|
|
}
|
|
|
|
return pointer_value, data, nil
|
|
}
|
|
|
|
func SerializeTypeStub(ctx *Context, reflect_type reflect.Type) ([]SerializedType, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func DeserializeTypeStub[T any](ctx *Context, type_stack []SerializedType) (reflect.Type, []SerializedType, error) {
|
|
var zero T
|
|
return reflect.TypeOf(zero), type_stack, nil
|
|
}
|
|
|
|
func SerializeTypeElem(ctx *Context, reflect_type reflect.Type) ([]SerializedType, error) {
|
|
return SerializeType(ctx, reflect_type.Elem())
|
|
}
|
|
|
|
func SerializeSlice(ctx *Context, value reflect.Value) (Chunks, error) {
|
|
if value.IsZero() {
|
|
return NewChunks([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}), nil
|
|
} else if value.Len() == 0 {
|
|
return NewChunks([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), nil
|
|
} else {
|
|
slice_chunks := Chunks{}
|
|
for i := 0; i < value.Len(); i += 1 {
|
|
val := value.Index(i)
|
|
element_chunks, err := SerializeValue(ctx, val)
|
|
if err != nil {
|
|
return Chunks{}, err
|
|
}
|
|
slice_chunks = slice_chunks.AddChunksToEnd(element_chunks)
|
|
}
|
|
|
|
size_data := make([]byte, 8)
|
|
binary.BigEndian.PutUint64(size_data, uint64(value.Len()))
|
|
|
|
return NewChunks(size_data).AddChunksToEnd(slice_chunks), nil
|
|
}
|
|
}
|
|
|
|
func DeserializeTypeSlice(ctx *Context, type_stack []SerializedType) (reflect.Type, []SerializedType, error) {
|
|
elem_type, remaining, err := DeserializeType(ctx, type_stack)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
reflect_type := reflect.SliceOf(elem_type)
|
|
return reflect_type, remaining, nil
|
|
}
|
|
|
|
func DeserializeSlice(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 slice %d/8", len(data))
|
|
}
|
|
|
|
slice_size := binary.BigEndian.Uint64(data[0:8])
|
|
slice_value := reflect.New(reflect_type).Elem()
|
|
data = data[8:]
|
|
|
|
if slice_size != 0xFFFFFFFFFFFFFFFF {
|
|
slice_unaddr := reflect.MakeSlice(reflect_type, int(slice_size), int(slice_size))
|
|
slice_value.Set(slice_unaddr)
|
|
for i := uint64(0); i < slice_size; i += 1 {
|
|
var element_value reflect.Value
|
|
var err error
|
|
element_value, data, err = DeserializeValue(ctx, reflect_type.Elem(), data)
|
|
if err != nil {
|
|
return reflect.Value{}, nil, err
|
|
}
|
|
|
|
slice_elem := slice_value.Index(int(i))
|
|
slice_elem.Set(element_value)
|
|
}
|
|
}
|
|
|
|
return slice_value, data, nil
|
|
}
|
|
|
|
func SerializeTypeMap(ctx *Context, reflect_type reflect.Type) ([]SerializedType, error) {
|
|
key_stack, err := SerializeType(ctx, reflect_type.Key())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
elem_stack, err := SerializeType(ctx, reflect_type.Elem())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return append(key_stack, elem_stack...), nil
|
|
}
|
|
|
|
func DeserializeTypeMap(ctx *Context, type_stack []SerializedType) (reflect.Type, []SerializedType, error) {
|
|
key_type, after_key, err := DeserializeType(ctx, type_stack)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
elem_type, after_elem, err := DeserializeType(ctx, after_key)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
map_type := reflect.MapOf(key_type, elem_type)
|
|
return map_type, after_elem, nil
|
|
}
|
|
|
|
func SerializeMap(ctx *Context, value reflect.Value) (Chunks, error) {
|
|
if value.IsZero() == true {
|
|
return NewChunks([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}), nil
|
|
}
|
|
|
|
map_chunks := []Chunks{}
|
|
map_size := uint64(0)
|
|
map_iter := value.MapRange()
|
|
for map_iter.Next() {
|
|
map_size = map_size + 1
|
|
key := map_iter.Key()
|
|
val := map_iter.Value()
|
|
|
|
key_chunks, err := SerializeValue(ctx, key)
|
|
if err != nil {
|
|
return Chunks{}, err
|
|
}
|
|
|
|
val_chunks, err := SerializeValue(ctx, val)
|
|
if err != nil {
|
|
return Chunks{}, err
|
|
}
|
|
|
|
chunks := key_chunks.AddChunksToEnd(val_chunks)
|
|
map_chunks = append(map_chunks, chunks)
|
|
}
|
|
|
|
// Sort map_chunks
|
|
sort.Slice(map_chunks, func(i, j int) bool {
|
|
return bytes.Compare(map_chunks[i].First.Data, map_chunks[j].First.Data) < 0
|
|
})
|
|
chunks := Chunks{}
|
|
for _, chunk := range(map_chunks) {
|
|
chunks = chunks.AddChunksToEnd(chunk)
|
|
}
|
|
|
|
|
|
size_data := make([]byte, 8)
|
|
binary.BigEndian.PutUint64(size_data, map_size)
|
|
|
|
return NewChunks(size_data).AddChunksToEnd(chunks), nil
|
|
}
|
|
|
|
func DeserializeMap(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 map %d/8", len(data))
|
|
}
|
|
|
|
size_bytes := data[:8]
|
|
data = data[8:]
|
|
|
|
size := binary.BigEndian.Uint64(size_bytes)
|
|
|
|
map_value := reflect.New(reflect_type).Elem()
|
|
if size == 0xFFFFFFFFFFFFFFFF {
|
|
return map_value, data, nil
|
|
}
|
|
|
|
map_unaddr := reflect.MakeMapWithSize(reflect_type, int(size))
|
|
map_value.Set(map_unaddr)
|
|
|
|
for i := uint64(0); i < size; i++ {
|
|
var err error
|
|
var key_value reflect.Value
|
|
key_value, data, err = DeserializeValue(ctx, reflect_type.Key(), data)
|
|
if err != nil {
|
|
return reflect.Value{}, nil, err
|
|
}
|
|
|
|
var val_value reflect.Value
|
|
val_value, data, err = DeserializeValue(ctx, reflect_type.Elem(), data)
|
|
if err != nil {
|
|
return reflect.Value{}, nil, err
|
|
}
|
|
|
|
map_value.SetMapIndex(key_value, val_value)
|
|
}
|
|
|
|
return map_value, data, nil
|
|
}
|
|
|
|
func SerializeTypeArray(ctx *Context, reflect_type reflect.Type) ([]SerializedType, error) {
|
|
size := SerializedType(reflect_type.Len())
|
|
elem_stack, err := SerializeType(ctx, reflect_type.Elem())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return append([]SerializedType{size}, elem_stack...), nil
|
|
}
|
|
|
|
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_chunks, err := SerializeValue(ctx, element)
|
|
if err != nil {
|
|
return Chunks{}, err
|
|
}
|
|
data = data.AddChunksToEnd(element_chunks)
|
|
}
|
|
|
|
return data, nil
|
|
}
|
|
|
|
func DeserializeTypeArray(ctx *Context, type_stack []SerializedType) (reflect.Type, []SerializedType, error) {
|
|
if len(type_stack) < 1 {
|
|
return nil, nil, fmt.Errorf("Not enough valued in type stack to deserialize array")
|
|
}
|
|
|
|
size := int(type_stack[0])
|
|
element_type, remaining, err := DeserializeType(ctx, type_stack[1:])
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
array_type := reflect.ArrayOf(size, element_type)
|
|
return array_type, remaining, nil
|
|
}
|
|
|
|
func DeserializeArray(ctx *Context, reflect_type reflect.Type, data []byte) (reflect.Value, []byte, error) {
|
|
array_value := reflect.New(reflect_type).Elem()
|
|
for i := 0; i < array_value.Len(); i += 1 {
|
|
var element_value reflect.Value
|
|
var err error
|
|
element_value, data, err = DeserializeValue(ctx, reflect_type.Elem(), data)
|
|
if err != nil {
|
|
return reflect.Value{}, nil, err
|
|
}
|
|
|
|
element := array_value.Index(i)
|
|
element.Set(element_value)
|
|
}
|
|
|
|
return array_value, data, nil
|
|
}
|
|
|
|
func SerializeInterface(ctx *Context, value reflect.Value) (Chunks, error) {
|
|
if value.IsZero() == true {
|
|
return NewChunks([]byte{0xFF}), nil
|
|
}
|
|
|
|
type_stack, err := SerializeType(ctx, value.Elem().Type())
|
|
if err != nil {
|
|
return Chunks{}, err
|
|
}
|
|
|
|
elem_chunks, err := SerializeValue(ctx, value.Elem())
|
|
if err != nil {
|
|
return Chunks{}, err
|
|
}
|
|
|
|
data := elem_chunks.Slice()
|
|
|
|
serialized_chunks, err := SerializedValue{type_stack, data}.Chunks()
|
|
if err != nil {
|
|
return Chunks{}, err
|
|
}
|
|
|
|
return NewChunks([]byte{0x00}).AddChunksToEnd(serialized_chunks), nil
|
|
}
|
|
|
|
func DeserializeInterface(ctx *Context, reflect_type reflect.Type, data []byte) (reflect.Value, []byte, error) {
|
|
if len(data) < 1 {
|
|
return reflect.Value{}, nil, fmt.Errorf("Not enough data to deserialize interface %d/1", len(data))
|
|
}
|
|
|
|
flags := data[0]
|
|
data = data[1:]
|
|
if flags == 0xFF {
|
|
return reflect.New(reflect_type).Elem(), data, nil
|
|
}
|
|
|
|
serialized_value, remaining, err := ParseSerializedValue(data)
|
|
elem_type, types_remaining, err := DeserializeType(ctx, serialized_value.TypeStack)
|
|
if err != nil {
|
|
return reflect.Value{}, nil, err
|
|
} else if len(types_remaining) > 0 {
|
|
return reflect.Value{}, nil, fmt.Errorf("Types remaining in interface stack after deserializing")
|
|
}
|
|
|
|
elem_value, data_remaining, err := DeserializeValue(ctx, elem_type, serialized_value.Data)
|
|
if err != nil {
|
|
return reflect.Value{}, nil, err
|
|
} else if len(data_remaining) > 0 {
|
|
return reflect.Value{}, nil, fmt.Errorf("Data remaining in interface data after deserializing")
|
|
}
|
|
|
|
interface_value := reflect.New(reflect_type).Elem()
|
|
interface_value.Set(elem_value)
|
|
|
|
return interface_value, remaining, nil
|
|
}
|
|
|
|
type SerializedValue struct {
|
|
TypeStack []SerializedType
|
|
Data []byte
|
|
}
|
|
|
|
func SerializeAny[T any](ctx *Context, value T) (SerializedValue, error) {
|
|
reflect_value := reflect.ValueOf(value)
|
|
type_stack, err := SerializeType(ctx, reflect_value.Type())
|
|
if err != nil {
|
|
return SerializedValue{}, err
|
|
}
|
|
data, err := SerializeValue(ctx, reflect_value)
|
|
if err != nil {
|
|
return SerializedValue{}, err
|
|
}
|
|
|
|
return SerializedValue{type_stack, data.Slice()}, nil
|
|
}
|
|
|
|
func SerializeType(ctx *Context, reflect_type reflect.Type) ([]SerializedType, error) {
|
|
ctx.Log.Logf("serialize", "Serializing type %+v", reflect_type)
|
|
|
|
type_info, type_exists := ctx.TypeReflects[reflect_type]
|
|
var serialize_type TypeSerializeFn = nil
|
|
var ctx_type SerializedType
|
|
if type_exists == true {
|
|
serialize_type = type_info.TypeSerialize
|
|
ctx_type = type_info.Type
|
|
}
|
|
|
|
if serialize_type == nil {
|
|
kind_info, handled := ctx.Kinds[reflect_type.Kind()]
|
|
if handled == true {
|
|
if type_exists == false {
|
|
ctx_type = kind_info.Type
|
|
}
|
|
serialize_type = kind_info.TypeSerialize
|
|
}
|
|
}
|
|
|
|
type_stack := []SerializedType{ctx_type}
|
|
if serialize_type != nil {
|
|
extra_types, err := serialize_type(ctx, reflect_type)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return append(type_stack, extra_types...), nil
|
|
} else {
|
|
return type_stack, nil
|
|
}
|
|
}
|
|
|
|
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 {
|
|
if type_info.Serialize != nil {
|
|
serialize = type_info.Serialize
|
|
}
|
|
}
|
|
|
|
if serialize == nil {
|
|
kind_info, handled := ctx.Kinds[value.Kind()]
|
|
if handled {
|
|
serialize = kind_info.Serialize
|
|
} else {
|
|
return Chunks{}, fmt.Errorf("Don't know how to serialize %+v", value.Type())
|
|
}
|
|
}
|
|
|
|
return serialize(ctx, value)
|
|
}
|
|
|
|
func ExtField(ctx *Context, ext Extension, field_name string) (reflect.Value, error) {
|
|
if ext == nil {
|
|
return reflect.Value{}, fmt.Errorf("Cannot get fields on nil Extension")
|
|
}
|
|
|
|
ext_value := reflect.ValueOf(ext).Elem()
|
|
for _, field := range reflect.VisibleFields(ext_value.Type()) {
|
|
gv_tag, tagged := field.Tag.Lookup("gv")
|
|
if tagged == true && gv_tag == field_name {
|
|
return ext_value.FieldByIndex(field.Index), nil
|
|
}
|
|
}
|
|
|
|
return reflect.Value{}, fmt.Errorf("%s is not a field in %+v", field_name, reflect.TypeOf(ext))
|
|
}
|
|
|
|
func SerializeField(ctx *Context, ext Extension, field_name string) (SerializedValue, error) {
|
|
field_value, err := ExtField(ctx, ext, field_name)
|
|
if err != nil {
|
|
return SerializedValue{}, err
|
|
}
|
|
type_stack, err := SerializeType(ctx, field_value.Type())
|
|
if err != nil {
|
|
return SerializedValue{}, err
|
|
}
|
|
data, err := SerializeValue(ctx, field_value)
|
|
if err != nil {
|
|
return SerializedValue{}, err
|
|
}
|
|
return SerializedValue{type_stack, data.Slice()}, nil
|
|
}
|
|
|
|
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)))
|
|
|
|
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 NewChunks(header_data).AddDataToEnd(type_stack_bytes...).AddDataToEnd(value.Data), nil
|
|
}
|
|
|
|
func ParseSerializedValue(data []byte) (SerializedValue, []byte, error) {
|
|
if len(data) < 8 {
|
|
return SerializedValue{}, nil, fmt.Errorf("SerializedValue required to have at least 8 bytes when serialized")
|
|
}
|
|
num_types := int(binary.BigEndian.Uint64(data[0:8]))
|
|
data_size := int(binary.BigEndian.Uint64(data[8:16]))
|
|
type_stack := make([]SerializedType, num_types)
|
|
for i := 0; i < num_types; i += 1 {
|
|
type_start := (i + 2) * 8
|
|
type_end := (i + 3) * 8
|
|
type_stack[i] = SerializedType(binary.BigEndian.Uint64(data[type_start:type_end]))
|
|
}
|
|
|
|
types_end := 8 * (num_types + 2)
|
|
data_end := types_end + data_size
|
|
return SerializedValue{
|
|
type_stack,
|
|
data[types_end:data_end],
|
|
}, data[data_end:], nil
|
|
}
|
|
|
|
func DeserializeValue(ctx *Context, reflect_type reflect.Type, data []byte) (reflect.Value, []byte, error) {
|
|
ctx.Log.Logf("serialize", "Deserializing %+v with %d bytes", reflect_type, len(data))
|
|
var deserialize DeserializeFn = nil
|
|
|
|
type_info, type_exists := ctx.TypeReflects[reflect_type]
|
|
if type_exists == true {
|
|
deserialize = type_info.Deserialize
|
|
} else {
|
|
kind_info, exists := ctx.Kinds[reflect_type.Kind()]
|
|
if exists == false {
|
|
return reflect.Value{}, nil, fmt.Errorf("Cannot deserialize %+v/%+v: unknown type/kind", reflect_type, reflect_type.Kind())
|
|
}
|
|
deserialize = kind_info.Deserialize
|
|
}
|
|
|
|
return deserialize(ctx, reflect_type, data)
|
|
}
|
|
|
|
func DeserializeType(ctx *Context, type_stack []SerializedType) (reflect.Type, []SerializedType, error) {
|
|
ctx.Log.Logf("deserialize_types", "Deserializing type stack %+v", type_stack)
|
|
var deserialize_type TypeDeserializeFn = nil
|
|
var reflect_type reflect.Type = nil
|
|
|
|
if len(type_stack) < 1 {
|
|
return nil, nil, fmt.Errorf("No elements in type stack to deserialize(DeserializeType)")
|
|
}
|
|
|
|
ctx_type := type_stack[0]
|
|
type_stack = type_stack[1:]
|
|
|
|
type_info, type_exists := ctx.Types[SerializedType(ctx_type)]
|
|
if type_exists == true {
|
|
deserialize_type = type_info.TypeDeserialize
|
|
reflect_type = type_info.Reflect
|
|
} else {
|
|
kind_info, exists := ctx.KindTypes[SerializedType(ctx_type)]
|
|
if exists == false {
|
|
return nil, nil, fmt.Errorf("Cannot deserialize 0x%x: unknown type/kind", ctx_type)
|
|
}
|
|
deserialize_type = kind_info.TypeDeserialize
|
|
reflect_type = kind_info.Base
|
|
}
|
|
|
|
if deserialize_type == nil {
|
|
return reflect_type, type_stack, nil
|
|
} else {
|
|
return deserialize_type(ctx, type_stack)
|
|
}
|
|
}
|