Added graphiql command, fixed map GQL naming, and made serialization interface use generics

gql_cataclysm
noah metz 2024-03-08 14:35:23 -07:00
parent 7314c74087
commit 7e143c9d93
5 changed files with 144 additions and 122 deletions

@ -0,0 +1,35 @@
package main
import (
"fmt"
badger "github.com/dgraph-io/badger/v3"
gv "github.com/mekkanized/graphvent"
)
func check(err error) {
if err != nil {
panic(err)
}
}
func main() {
db, err := badger.Open(badger.DefaultOptions("").WithInMemory(true))
check(err)
ctx, err := gv.NewContext(db, gv.NewConsoleLogger([]string{"test", "gql"}))
check(err)
gql_ext, err := gv.NewGQLExt(ctx, ":8080", nil, nil)
check(err)
listener_ext := gv.NewListenerExt(1000)
_, err = gv.NewNode(ctx, nil, "Base", 1000, gql_ext, listener_ext)
check(err)
select {
case message := <- listener_ext.Chan:
fmt.Printf("Listener Message: %+v\n", message)
}
}

@ -92,56 +92,63 @@ type Context struct {
nodeMap map[NodeID]*Node nodeMap map[NodeID]*Node
} }
func (ctx *Context) GQLType(t reflect.Type) graphql.Type { func (ctx *Context) GQLType(t reflect.Type) (graphql.Type, error) {
info, mapped := ctx.TypeTypes[t] info, mapped := ctx.TypeTypes[t]
if mapped { if mapped {
return info.Type return info.Type, nil
} else { } else {
switch t.Kind() { switch t.Kind() {
case reflect.Array: case reflect.Array:
info, mapped := ctx.TypeTypes[t.Elem()] info, mapped := ctx.TypeTypes[t.Elem()]
if mapped { if mapped {
return graphql.NewList(info.Type) return graphql.NewList(info.Type), nil
} }
case reflect.Slice: case reflect.Slice:
info, mapped := ctx.TypeTypes[t.Elem()] info, mapped := ctx.TypeTypes[t.Elem()]
if mapped { if mapped {
return graphql.NewList(info.Type) return graphql.NewList(info.Type), nil
} }
case reflect.Map: case reflect.Map:
info, exists := ctx.TypeTypes[t] info, exists := ctx.TypeTypes[t]
if exists { if exists {
return info.Type return info.Type, nil
} else { } else {
err := RegisterMap(ctx, t) err := RegisterMap(ctx, t)
if err != nil { if err != nil {
return nil return nil, err
} }
return ctx.TypeTypes[t].Type map_type := ctx.TypeTypes[t].Type
ctx.Log.Logf("gql", "Getting type for %s: %s", t, map_type)
return map_type, nil
} }
case reflect.Pointer: case reflect.Pointer:
info, mapped := ctx.TypeTypes[t.Elem()] info, mapped := ctx.TypeTypes[t.Elem()]
if mapped { if mapped {
return info.Type return info.Type, nil
} }
} }
return nil return nil, fmt.Errorf("Can't convert %s to GQL type", t)
} }
} }
func RegisterMap(ctx *Context, reflect_type reflect.Type) error { func RegisterMap(ctx *Context, reflect_type reflect.Type) error {
key_type := ctx.GQLType(reflect_type.Key()) key_type, err := ctx.GQLType(reflect_type.Key())
if key_type == nil { if err != nil {
return nil return err
} }
val_type := ctx.GQLType(reflect_type.Elem()) val_type, err := ctx.GQLType(reflect_type.Elem())
if val_type == nil { if err != nil {
return nil return err
} }
gql_name := strings.ReplaceAll(reflect_type.String(), ".", "_")
gql_name = strings.ReplaceAll(gql_name, "[", "_")
gql_name = strings.ReplaceAll(gql_name, "]", "_")
ctx.Log.Logf("gql", "Registering %s with gql name %s", reflect_type, gql_name)
gql_pair := graphql.NewObject(graphql.ObjectConfig{ gql_pair := graphql.NewObject(graphql.ObjectConfig{
Name: strings.ReplaceAll(reflect_type.String(), ".", "_"), Name: gql_name,
Fields: graphql.Fields{ Fields: graphql.Fields{
"Key": &graphql.Field{ "Key": &graphql.Field{
Type: key_type, Type: key_type,
@ -158,6 +165,7 @@ func RegisterMap(ctx *Context, reflect_type reflect.Type) error {
}, },
}) })
ctx.Log.Logf("gql", "Registering new map with pair type %+v", gql_pair)
gql_map := graphql.NewList(gql_pair) gql_map := graphql.NewList(gql_pair)
serialized_type := SerializeType(reflect_type) serialized_type := SerializeType(reflect_type)
@ -227,8 +235,10 @@ func RegisterExtension[E any, T interface { *E; Extension}](ctx *Context, data i
return fmt.Errorf("Cannot register extension %+v of type %+v, type already exists in context", reflect_type, ext_type) return fmt.Errorf("Cannot register extension %+v of type %+v, type already exists in context", reflect_type, ext_type)
} }
gql_name := "interface_" + strings.ReplaceAll(reflect_type.String(), ".", "_")
ctx.Log.Logf("gql", "Registering %s with gql name %s", reflect_type, gql_name)
gql_interface := graphql.NewInterface(graphql.InterfaceConfig{ gql_interface := graphql.NewInterface(graphql.InterfaceConfig{
Name: "interface_" + strings.ReplaceAll(reflect_type.String(), ".", "_"), Name: gql_name,
ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object {
ctx, ok := p.Context.Value("resolve").(*ResolveContext) ctx, ok := p.Context.Value("resolve").(*ResolveContext)
if ok == false { if ok == false {
@ -260,9 +270,9 @@ func RegisterExtension[E any, T interface { *E; Extension}](ctx *Context, data i
if tagged_gv { if tagged_gv {
fields[gv_tag] = field.Index fields[gv_tag] = field.Index
gql_type := ctx.GQLType(field.Type) gql_type, err := ctx.GQLType(field.Type)
if gql_type == nil { if err != nil {
return fmt.Errorf("Extension %s has field %s of unregistered type %s", reflect_type, gv_tag, field.Type) return err
} }
gql_interface.AddFieldConfig(gv_tag, &graphql.Field{ gql_interface.AddFieldConfig(gv_tag, &graphql.Field{
@ -347,8 +357,10 @@ func RegisterObject[T any](ctx *Context) error {
return fmt.Errorf("%+v already registered in TypeMap", reflect_type) return fmt.Errorf("%+v already registered in TypeMap", reflect_type)
} }
gql_name := strings.ReplaceAll(reflect_type.String(), ".", "_")
ctx.Log.Logf("gql", "Registering %s with gql name %s", reflect_type, gql_name)
gql := graphql.NewObject(graphql.ObjectConfig{ gql := graphql.NewObject(graphql.ObjectConfig{
Name: strings.ReplaceAll(reflect_type.String(), ".", "_"), Name: gql_name,
IsTypeOf: func(p graphql.IsTypeOfParams) bool { IsTypeOf: func(p graphql.IsTypeOfParams) bool {
return reflect_type == reflect.TypeOf(p.Value) return reflect_type == reflect.TypeOf(p.Value)
}, },
@ -372,9 +384,9 @@ func RegisterObject[T any](ctx *Context) error {
Index: field.Index, Index: field.Index,
} }
gql_type := ctx.GQLType(field.Type) gql_type, err := ctx.GQLType(field.Type)
if gql_type == nil { if err != nil {
return fmt.Errorf("Object %+v has field %s of unknown type %+v", reflect_type, gv_tag, field.Type) return err
} }
gql.AddFieldConfig(gv_tag, &graphql.Field{ gql.AddFieldConfig(gv_tag, &graphql.Field{
Type: gql_type, Type: gql_type,
@ -532,8 +544,10 @@ func RegisterScalar[S any](ctx *Context, to_json func(interface{})interface{}, f
return fmt.Errorf("%+v already registered in TypeMap", reflect_type) return fmt.Errorf("%+v already registered in TypeMap", reflect_type)
} }
gql_name := strings.ReplaceAll(reflect_type.String(), ".", "_")
ctx.Log.Logf("gql", "Registering %s with gql name %s", reflect_type, gql_name)
gql := graphql.NewScalar(graphql.ScalarConfig{ gql := graphql.NewScalar(graphql.ScalarConfig{
Name: strings.ReplaceAll(reflect_type.String(), ".", "_"), Name: gql_name,
Serialize: to_json, Serialize: to_json,
ParseValue: from_json, ParseValue: from_json,
ParseLiteral: from_ast, ParseLiteral: from_ast,
@ -726,22 +740,17 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) {
return nil, err return nil, err
} }
err = RegisterMap(ctx, reflect.TypeFor[WaitMap]()) err = RegisterExtension[LockableExt](ctx, nil)
if err != nil {
return nil, err
}
err = RegisterExtension[ListenerExt](ctx, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = RegisterExtension[LockableExt](ctx, nil) err = RegisterExtension[EventExt](ctx, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = RegisterExtension[EventExt](ctx, nil) err = RegisterExtension[ListenerExt](ctx, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -756,7 +765,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) {
return nil, err return nil, err
} }
_, err = BuildSchema(ctx, graphql.NewObject(graphql.ObjectConfig{ schema, err := BuildSchema(ctx, graphql.NewObject(graphql.ObjectConfig{
Name: "Query", Name: "Query",
Fields: graphql.Fields{ Fields: graphql.Fields{
"Test": &graphql.Field{ "Test": &graphql.Field{
@ -781,5 +790,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) {
return nil, err return nil, err
} }
ctx.ExtensionTypes[reflect.TypeFor[GQLExt]()].Data = schema
return ctx, nil return ctx, nil
} }

15
db.go

@ -5,7 +5,12 @@ import (
) )
func WriteNodeInit(ctx *Context, node *Node) error { func WriteNodeInit(ctx *Context, node *Node) error {
return ctx.DB.Update(func(db *badger.Txn) error { return ctx.DB.Update(func(tx *badger.Txn) error {
_, err := node.ID.MarshalBinary()
if err != nil {
return err
}
// Write node private key // Write node private key
// Write node type // Write node type
// Write Node buffer size // Write Node buffer size
@ -17,8 +22,12 @@ func WriteNodeInit(ctx *Context, node *Node) error {
} }
func WriteNodeChanges(ctx *Context, node *Node, changes map[ExtType]Changes) error { func WriteNodeChanges(ctx *Context, node *Node, changes map[ExtType]Changes) error {
return ctx.DB.Update(func(db *badger.Txn) error { return ctx.DB.Update(func(tx *badger.Txn) error {
// Write the signal queue if it needs to be written // Write the signal queue if it needs to be written
if node.writeSignalQueue {
node.writeSignalQueue = false
}
// For each ext in changes // For each ext in changes
// Write each change // Write each change
return nil return nil
@ -26,7 +35,7 @@ func WriteNodeChanges(ctx *Context, node *Node, changes map[ExtType]Changes) err
} }
func LoadNode(ctx *Context, id NodeID) (*Node, error) { func LoadNode(ctx *Context, id NodeID) (*Node, error) {
err := ctx.DB.Update(func(db *badger.Txn) error { err := ctx.DB.Update(func(tx *badger.Txn) error {
return nil return nil
}) })

@ -190,7 +190,26 @@ func UnwrapStack(ctx *Context, stack []SerializedType) (reflect.Type, []Serializ
} }
} }
func SerializeValue(ctx *Context, value reflect.Value) ([]byte, error) { func Serialize[T any](ctx *Context, value T) ([]byte, error) {
return serializeValue(ctx, reflect.ValueOf(value))
}
func Deserialize[T any](ctx *Context, data []byte) (T, error) {
reflect_type := reflect.TypeFor[T]()
var zero T
value, left, err := deserializeValue(ctx, data, reflect_type)
if err != nil {
return zero, err
} else if len(left) != 0 {
return zero, fmt.Errorf("%d bytes left after deserializing %+v", len(left), value)
} else if value.Type() != reflect_type {
return zero, fmt.Errorf("Deserialized type %s does not match %s", value.Type(), reflect_type)
}
return value.Interface().(T), nil
}
func serializeValue(ctx *Context, value reflect.Value) ([]byte, error) {
var serialize SerializeFn = nil var serialize SerializeFn = nil
info, registered := ctx.TypeTypes[value.Type()] info, registered := ctx.TypeTypes[value.Type()]
@ -243,7 +262,7 @@ func SerializeValue(ctx *Context, value reflect.Value) ([]byte, error) {
if value.IsNil() { if value.IsNil() {
return []byte{0x00}, nil return []byte{0x00}, nil
} else { } else {
elem, err := SerializeValue(ctx, value.Elem()) elem, err := serializeValue(ctx, value.Elem())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -260,7 +279,7 @@ func SerializeValue(ctx *Context, value reflect.Value) ([]byte, error) {
data := []byte{} data := []byte{}
for i := 0; i < value.Len(); i++ { for i := 0; i < value.Len(); i++ {
elem, err := SerializeValue(ctx, value.Index(i)) elem, err := serializeValue(ctx, value.Index(i))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -274,7 +293,7 @@ func SerializeValue(ctx *Context, value reflect.Value) ([]byte, error) {
case reflect.Array: case reflect.Array:
data := []byte{} data := []byte{}
for i := 0; i < value.Len(); i++ { for i := 0; i < value.Len(); i++ {
elem, err := SerializeValue(ctx, value.Index(i)) elem, err := serializeValue(ctx, value.Index(i))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -290,14 +309,14 @@ func SerializeValue(ctx *Context, value reflect.Value) ([]byte, error) {
data := []byte{} data := []byte{}
iter := value.MapRange() iter := value.MapRange()
for iter.Next() { for iter.Next() {
k, err := SerializeValue(ctx, iter.Key()) k, err := serializeValue(ctx, iter.Key())
if err != nil { if err != nil {
return nil, err return nil, err
} }
data = append(data, k...) data = append(data, k...)
v, err := SerializeValue(ctx, iter.Value()) v, err := serializeValue(ctx, iter.Value())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -314,7 +333,7 @@ func SerializeValue(ctx *Context, value reflect.Value) ([]byte, error) {
for field_tag, field_info := range(info.Fields) { for field_tag, field_info := range(info.Fields) {
data = append(data, binary.BigEndian.AppendUint64(nil, uint64(field_tag))...) data = append(data, binary.BigEndian.AppendUint64(nil, uint64(field_tag))...)
field_bytes, err := SerializeValue(ctx, value.FieldByIndex(field_info.Index)) field_bytes, err := serializeValue(ctx, value.FieldByIndex(field_info.Index))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -336,7 +355,7 @@ func split(data []byte, n int) ([]byte, []byte) {
return data[:n], data[n:] return data[:n], data[n:]
} }
func DeserializeValue(ctx *Context, data []byte, t reflect.Type) (reflect.Value, []byte, error) { func deserializeValue(ctx *Context, data []byte, t reflect.Type) (reflect.Value, []byte, error) {
var deserialize DeserializeFn = nil var deserialize DeserializeFn = nil
info, registered := ctx.TypeTypes[t] info, registered := ctx.TypeTypes[t]
@ -423,7 +442,7 @@ func DeserializeValue(ctx *Context, data []byte, t reflect.Type) (reflect.Value,
value.SetZero() value.SetZero()
return value, after_flags, nil return value, after_flags, nil
} else { } else {
elem_value, after_elem, err := DeserializeValue(ctx, after_flags, t.Elem()) elem_value, after_elem, err := deserializeValue(ctx, after_flags, t.Elem())
if err != nil { if err != nil {
return reflect.Value{}, nil, err return reflect.Value{}, nil, err
} }
@ -438,7 +457,7 @@ func DeserializeValue(ctx *Context, data []byte, t reflect.Type) (reflect.Value,
for i := 0; i < length; i++ { for i := 0; i < length; i++ {
var elem_value reflect.Value var elem_value reflect.Value
var err error var err error
elem_value, left, err = DeserializeValue(ctx, left, t.Elem()) elem_value, left, err = deserializeValue(ctx, left, t.Elem())
if err != nil { if err != nil {
return reflect.Value{}, nil, err return reflect.Value{}, nil, err
} }
@ -452,7 +471,7 @@ func DeserializeValue(ctx *Context, data []byte, t reflect.Type) (reflect.Value,
for i := 0; i < t.Len(); i++ { for i := 0; i < t.Len(); i++ {
var elem_value reflect.Value var elem_value reflect.Value
var err error var err error
elem_value, left, err = DeserializeValue(ctx, left, t.Elem()) elem_value, left, err = deserializeValue(ctx, left, t.Elem())
if err != nil { if err != nil {
return reflect.Value{}, nil, err return reflect.Value{}, nil, err
} }
@ -471,12 +490,12 @@ func DeserializeValue(ctx *Context, data []byte, t reflect.Type) (reflect.Value,
var val_value reflect.Value var val_value reflect.Value
var err error var err error
key_value, left, err = DeserializeValue(ctx, left, t.Key()) key_value, left, err = deserializeValue(ctx, left, t.Key())
if err != nil { if err != nil {
return reflect.Value{}, nil, err return reflect.Value{}, nil, err
} }
val_value, left, err = DeserializeValue(ctx, left, t.Elem()) val_value, left, err = deserializeValue(ctx, left, t.Elem())
if err != nil { if err != nil {
return reflect.Value{}, nil, err return reflect.Value{}, nil, err
} }
@ -504,7 +523,7 @@ func DeserializeValue(ctx *Context, data []byte, t reflect.Type) (reflect.Value,
if mapped { if mapped {
var field_val reflect.Value var field_val reflect.Value
var err error var err error
field_val, left, err = DeserializeValue(ctx, left, field_info.Type) field_val, left, err = deserializeValue(ctx, left, field_info.Type)
if err != nil { if err != nil {
return reflect.Value{}, nil, err return reflect.Value{}, nil, err
} }

@ -41,123 +41,71 @@ func TestSerializeTypes(t *testing.T) {
} }
func testSerializeCompare[T comparable](t *testing.T, ctx *Context, value T) { func testSerializeCompare[T comparable](t *testing.T, ctx *Context, value T) {
serialized, err := SerializeValue(ctx, reflect.ValueOf(value)) serialized, err := Serialize(ctx, value)
fatalErr(t, err) fatalErr(t, err)
ctx.Log.Logf("test", "Serialized Value[%s : %+v]: %+v", reflect.TypeFor[T](), value, serialized) ctx.Log.Logf("test", "Serialized Value[%s : %+v]: %+v", reflect.TypeFor[T](), value, serialized)
deserialized, left, err := DeserializeValue(ctx, serialized, reflect.TypeFor[T]()) deserialized, err := Deserialize[T](ctx, serialized)
fatalErr(t, err) fatalErr(t, err)
if len(left) != 0 { if value != deserialized {
t.Fatalf("Data left after deserialize[%+v]: %+v", deserialized, left)
}
if reflect.TypeFor[T]() != deserialized.Type() {
t.Fatalf("Type mismatch after deserialize %s != %s", reflect.TypeFor[T](), deserialized.Type())
}
val, ok := deserialized.Interface().(T)
if ok == false {
t.Fatalf("Deserialized type[%s] can't cast to type %s", deserialized.Type(), reflect.TypeFor[T]())
}
if value != val {
t.Fatalf("Deserialized value[%+v] doesn't match original[%+v]", value, deserialized) t.Fatalf("Deserialized value[%+v] doesn't match original[%+v]", value, deserialized)
} }
ctx.Log.Logf("test", "Deserialized Value[%+v]: %+v", value, val) ctx.Log.Logf("test", "Deserialized Value[%+v]: %+v", value, deserialized)
} }
func testSerializeList[L []T, T comparable](t *testing.T, ctx *Context, value L) { func testSerializeList[L []T, T comparable](t *testing.T, ctx *Context, value L) {
serialized, err := SerializeValue(ctx, reflect.ValueOf(value)) serialized, err := Serialize(ctx, value)
fatalErr(t, err) fatalErr(t, err)
ctx.Log.Logf("test", "Serialized Value[%s : %+v]: %+v", reflect.TypeFor[L](), value, serialized) ctx.Log.Logf("test", "Serialized Value[%s : %+v]: %+v", reflect.TypeFor[L](), value, serialized)
deserialized, left, err := DeserializeValue(ctx, serialized, reflect.TypeFor[L]()) deserialized, err := Deserialize[L](ctx, serialized)
fatalErr(t, err) fatalErr(t, err)
if len(left) != 0 {
t.Fatalf("Data left after deserialize[%+v]: %+v", deserialized, left)
}
if reflect.TypeFor[L]() != deserialized.Type() {
t.Fatalf("Type mismatch after deserialize %s != %s", reflect.TypeFor[L](), deserialized.Type())
}
val, ok := deserialized.Interface().(L)
if ok == false {
t.Fatalf("Deserialized type[%s] can't cast to type %s", deserialized.Type(), reflect.TypeFor[L]())
}
for i, item := range(value) { for i, item := range(value) {
if item != val[i] { if item != deserialized[i] {
t.Fatalf("Deserialized list %+v does not match original %+v", value, val) t.Fatalf("Deserialized list %+v does not match original %+v", value, deserialized)
} }
} }
ctx.Log.Logf("test", "Deserialized Value[%+v]: %+v", value, val) ctx.Log.Logf("test", "Deserialized Value[%+v]: %+v", value, deserialized)
} }
func testSerializePointer[P interface {*T}, T comparable](t *testing.T, ctx *Context, value P) { func testSerializePointer[P interface {*T}, T comparable](t *testing.T, ctx *Context, value P) {
serialized, err := SerializeValue(ctx, reflect.ValueOf(value)) serialized, err := Serialize(ctx, value)
fatalErr(t, err) fatalErr(t, err)
ctx.Log.Logf("test", "Serialized Value[%s : %+v]: %+v", reflect.TypeFor[P](), value, serialized) ctx.Log.Logf("test", "Serialized Value[%s : %+v]: %+v", reflect.TypeFor[P](), value, serialized)
deserialized, left, err := DeserializeValue(ctx, serialized, reflect.TypeFor[P]()) deserialized, err := Deserialize[P](ctx, serialized)
fatalErr(t, err) fatalErr(t, err)
if len(left) != 0 { if value == nil && deserialized == nil {
t.Fatalf("Data left after deserialize[%+v]: %+v", deserialized, left)
}
if reflect.TypeFor[P]() != deserialized.Type() {
t.Fatalf("Type mismatch after deserialize %s != %s", reflect.TypeFor[P](), deserialized.Type())
}
val, ok := deserialized.Interface().(P)
if ok == false {
t.Fatalf("Deserialized type[%s] can't cast to type %s", deserialized.Type(), reflect.TypeFor[P]())
}
if value == nil && val == nil {
ctx.Log.Logf("test", "Deserialized nil") ctx.Log.Logf("test", "Deserialized nil")
} else if value == nil { } else if value == nil {
t.Fatalf("Non-nil value[%+v] returned for nil value", val) t.Fatalf("Non-nil value[%+v] returned for nil value", deserialized)
} else if val == nil { } else if deserialized == nil {
t.Fatalf("Nil value returned for non-nil value[%+v]", value) t.Fatalf("Nil value returned for non-nil value[%+v]", value)
} else if *val != *value { } else if *deserialized != *value {
t.Fatalf("Deserialized value[%+v] doesn't match original[%+v]", value, deserialized) t.Fatalf("Deserialized value[%+v] doesn't match original[%+v]", value, deserialized)
} else { } else {
ctx.Log.Logf("test", "Deserialized Value[%+v]: %+v", *value, *val) ctx.Log.Logf("test", "Deserialized Value[%+v]: %+v", *value, *deserialized)
} }
} }
func testSerialize[T any](t *testing.T, ctx *Context, value T) { func testSerialize[T any](t *testing.T, ctx *Context, value T) {
serialized, err := SerializeValue(ctx, reflect.ValueOf(value)) serialized, err := Serialize(ctx, value)
fatalErr(t, err) fatalErr(t, err)
ctx.Log.Logf("test", "Serialized Value[%s : %+v]: %+v", reflect.TypeFor[T](), value, serialized) ctx.Log.Logf("test", "Serialized Value[%s : %+v]: %+v", reflect.TypeFor[T](), value, serialized)
deserialized, left, err := DeserializeValue(ctx, serialized, reflect.TypeFor[T]()) deserialized, err := Deserialize[T](ctx, serialized)
fatalErr(t, err) fatalErr(t, err)
if len(left) != 0 { ctx.Log.Logf("test", "Deserialized Value[%+v]: %+v", value, deserialized)
t.Fatalf("Data left after deserialize[%+v]: %+v", deserialized, left)
}
if reflect.TypeFor[T]() != deserialized.Type() {
t.Fatalf("Type mismatch after deserialize %s != %s", reflect.TypeFor[T](), deserialized.Type())
}
val, ok := deserialized.Interface().(T)
if ok == false {
t.Fatalf("Deserialized type[%s] can't cast to type %s", deserialized.Type(), reflect.TypeFor[T]())
}
ctx.Log.Logf("test", "Deserialized Value[%+v]: %+v", value, val)
} }
func TestSerializeValues(t *testing.T) { func TestSerializeValues(t *testing.T) {