v23+mojo: vdl -> mojo type conversion + tests for vdl <-> mojo type conv
This branch depends on the struct offset fixes going in.
Change-Id: Iae6d7bb42a5c890600519b9264151db3f9e1377c
diff --git a/go/src/v.io/x/mojo/transcoder/mojom_to_vdl.go b/go/src/v.io/x/mojo/transcoder/mojom_to_vdl.go
index a0bc9bb..feaf017 100644
--- a/go/src/v.io/x/mojo/transcoder/mojom_to_vdl.go
+++ b/go/src/v.io/x/mojo/transcoder/mojom_to_vdl.go
@@ -17,6 +17,8 @@
// the desired value. The datatype describes the type of the encoded data.
// Returns an error if the data cannot be decoded into valptr, based on the VDL
// value conversion rules.
+// TODO(bprosnitz) Consider reimplementing this using mojom_type instead of vdl type
+// so that we can take advantage of the struct offset in the mojom type.
func MojomToVdl(data []byte, datatype *vdl.Type, valptr interface{}) error {
target, err := vdl.ReflectTarget(reflect.ValueOf(valptr))
if err != nil {
diff --git a/go/src/v.io/x/mojo/transcoder/transcoder_test.go b/go/src/v.io/x/mojo/transcoder/transcoder_test.go
index 0c634e3..ee262ac 100644
--- a/go/src/v.io/x/mojo/transcoder/transcoder_test.go
+++ b/go/src/v.io/x/mojo/transcoder/transcoder_test.go
@@ -59,6 +59,28 @@
}
}
+func TestVomToMojoToVom(t *testing.T) {
+ for _, test := range testCases {
+ testName := test.Name + " vom->mojo->vom"
+
+ data, err := transcoder.VdlToMojom(test.VdlValue)
+ if err != nil {
+ t.Errorf("%s: error in VomToMojo: %v", testName, err)
+ continue
+ }
+
+ var out interface{}
+ if err := transcoder.MojomToVdl(data, vdl.TypeOf(test.VdlValue), &out); err != nil {
+ t.Errorf("%s: error in MojoToVom: %v (was transcoding from %x)", testName, err, data)
+ continue
+ }
+
+ if got, want := out, test.VdlValue; !reflect.DeepEqual(got, want) {
+ t.Errorf("%s: result doesn't match expectation. got %#v, but want %#v", testName, got, want)
+ }
+ }
+}
+
func mojoEncode(mojoValue interface{}) ([]byte, error) {
payload, ok := mojoValue.(encodable)
if !ok {
diff --git a/go/src/v.io/x/mojo/transcoder/type.go b/go/src/v.io/x/mojo/transcoder/type.go
index 1b9a624..128b75e 100644
--- a/go/src/v.io/x/mojo/transcoder/type.go
+++ b/go/src/v.io/x/mojo/transcoder/type.go
@@ -93,11 +93,11 @@
case mojom_types.SimpleType_Bool:
vt = vdl.BoolType
case mojom_types.SimpleType_Double:
- vt = vdl.BoolType
+ vt = vdl.Float64Type
case mojom_types.SimpleType_Float:
- vt = vdl.BoolType
+ vt = vdl.Float32Type
case mojom_types.SimpleType_InT8:
- panic("int8 doesn't exist in vdl")
+ vt = vdl.Int8Type
case mojom_types.SimpleType_InT16:
vt = vdl.Int16Type
case mojom_types.SimpleType_InT32:
@@ -155,111 +155,164 @@
return vt
}
-/*func V2M(vt *vdl.Type, v2M map[string]string) mojom_types.Type {
- if m, ok := v2M[vt.String()]; ok {
- return mojom_types.TypeTypeReference{
- Value: mojom_types.TypeReference{
- Nullable: nullable,
- Identifier: m,
- TypeKey: m,
- },
- }
- }
- panic("vdl type %#v was not present in the mapping", vt)
+func VDLToMojomType(t *vdl.Type) (mojomtype mojom_types.Type, mp map[string]mojom_types.UserDefinedType) {
+ mp = map[string]mojom_types.UserDefinedType{}
+ mojomtype = vdlToMojomTypeInternal(t, false, mp)
+ return
}
-// From the vdltype and the reverse mapping of the descriptor (hashcons vdltype string => typekey),
-// produce the corresponding mojom Type.
-func VDLToMojomType(vt *vdl.Type, v2M map[string]string) mojom_types.Type {
- return vdlToMojomTypeImpl(vt, v2M, false)
-}
-
-func vdlToMojomTypeImpl(vt *vdl.Type, v2M map[string]string, bool nullable) mojom_types.Type {
- if m, ok := v2M[vt.String()]; ok {
- return mojom_types.TypeTypeReference{
- Value: mojom_types.TypeReference{
- Nullable: nullable,
- Identifier: m,
- TypeKey: m,
- },
+func vdlToMojomTypeInternal(t *vdl.Type, nullable bool, mp map[string]mojom_types.UserDefinedType) (mojomtype mojom_types.Type) {
+ switch t.Kind() {
+ case vdl.Bool, vdl.Float64, vdl.Float32, vdl.Int8, vdl.Int16, vdl.Int32, vdl.Int64, vdl.Byte, vdl.Uint16, vdl.Uint32, vdl.Uint64:
+ return &mojom_types.TypeSimpleType{
+ simpleTypeCode(t.Kind()),
}
- }
-
- fmt.Println("Missed the vdl to mojom map")
- // In the unlikely case where v2M was insufficient, we have the remaining logic.
-
- switch vt.Kind() {
- case vdl.Bool:
- return mojom_types.TypeSimpleType{Value: mojom_types.SimpleType_Bool}
- case vdl.Byte:
- return mojom_types.TypeSimpleType{Value: mojom_types.SimpleType_UinT8}
- case vdl.Uint16:
- return mojom_types.TypeSimpleType{Value: mojom_types.SimpleType_UinT16}
- case vdl.Uint32:
- return mojom_types.TypeSimpleType{Value: mojom_types.SimpleType_UinT32}
- case vdl.Uint64:
- return mojom_types.TypeSimpleType{Value: mojom_types.SimpleType_UinT64}
- case vdl.Int16:
- return mojom_types.TypeSimpleType{Value: mojom_types.SimpleType_InT16}
- case vdl.Int32:
- return mojom_types.TypeSimpleType{Value: mojom_types.SimpleType_InT32}
- case vdl.Int64:
- return mojom_types.TypeSimpleType{Value: mojom_types.SimpleType_InT64}
- case vdl.Float32:
- return mojom_types.TypeSimpleType{Value: mojom_types.SimpleType_Float}
- case vdl.Float64:
- return mojom_types.TypeSimpleType{Value: mojom_types.SimpleType_Double}
- case vdl.Complex64:
- panic("complex float doesn't exist in mojom")
- case vdl.Complex128:
- panic("complex double doesn't exist in mojom")
case vdl.String:
- return mojom_types.TypeStringType{Value: mojom_types.StringType{}}
+ return &mojom_types.TypeStringType{
+ stringType(nullable),
+ }
case vdl.Array:
- elemType := VDLToMojomType(vt.Elem(), v2M)
- return mojom_types.TypeArrayType{
- Value: mojom_types.ArrayType{
- FixedLength: int64(vt.Len()),
- ElementType: elemType,
- },
+ elem := vdlToMojomTypeInternal(t.Elem(), false, mp)
+ return &mojom_types.TypeArrayType{
+ arrayType(elem, nullable, t.Len()),
}
case vdl.List:
- elemType := VDLToMojomType(vt.Elem(), v2M)
- return mojom_types.TypeArrayType{
- Value: mojom_types.ArrayType{
- FixedLength: -1,
- ElementType: elemType,
- },
+ elem := vdlToMojomTypeInternal(t.Elem(), false, mp)
+ return &mojom_types.TypeArrayType{
+ listType(elem, nullable),
}
- case vdl.Set:
- panic("set doesn't exist in mojom")
case vdl.Map:
- keyType := VDLToMojomType(vt.Key(), v2M)
- elemType := VDLToMojomType(vt.Elem(), v2M)
- return mojom_types.TypeMapType{
- Value: mojom_types.MapType{
- KeyType: &keyType,
- ValueType: &elemType,
- },
+ key := vdlToMojomTypeInternal(t.Key(), false, mp)
+ elem := vdlToMojomTypeInternal(t.Elem(), false, mp)
+ return &mojom_types.TypeMapType{
+ mapType(key, elem, nullable),
}
case vdl.Struct, vdl.Union, vdl.Enum:
- mt := mojom_types.TypeTypeReference{
- Value: mojom_types.TypeReference{
- Nullable: nullable,
- Identifier: v2M[vt.String()],
- TypeKey: v2M[vt.String()],
+ udtKey := userDefinedTypeKey(t, mp)
+ return &mojom_types.TypeTypeReference{
+ mojom_types.TypeReference{
+ Nullable: nullable,
+ TypeKey: &udtKey,
},
}
- return mt
- case vdl.TypeObject:
- panic("typeobject doesn't exist in mojom")
- case vdl.Any:
- panic("any doesn't exist in mojom")
case vdl.Optional:
- // TODO(alexfandrianto): Unfortunately, without changing vdl, we can only
- // manage optional (named) structs. This doesn't Nullify anything else.
- return vdlToMojomTypeImpl(vt.Elem(), v2M, true)
+ return vdlToMojomTypeInternal(t.Elem(), true, mp)
+ default:
+ panic(fmt.Sprintf("conversion from VDL kind %v to mojom type not implemented", t.Kind()))
}
- panic(fmt.Errorf("%v can't be converted to MojomType", vt))
}
-*/
+
+func userDefinedTypeKey(t *vdl.Type, mp map[string]mojom_types.UserDefinedType) string {
+ key := t.String()
+ if _, ok := mp[key]; ok {
+ return key
+ }
+ mp[key] = nil // placeholder to stop recursion
+
+ var udt mojom_types.UserDefinedType
+ switch t.Kind() {
+ case vdl.Struct:
+ udt = structType(t, mp)
+ case vdl.Union:
+ udt = unionType(t, mp)
+ case vdl.Enum:
+ udt = enumType(t)
+ default:
+ panic(fmt.Sprintf("conversion from VDL kind %v to mojom user defined type not implemented", t.Kind()))
+ }
+
+ mp[key] = udt
+ return key
+}
+
+func simpleTypeCode(k vdl.Kind) mojom_types.SimpleType {
+ switch k {
+ case vdl.Bool:
+ return mojom_types.SimpleType_Bool
+ case vdl.Float64:
+ return mojom_types.SimpleType_Double
+ case vdl.Float32:
+ return mojom_types.SimpleType_Float
+ case vdl.Int8:
+ return mojom_types.SimpleType_InT8
+ case vdl.Int16:
+ return mojom_types.SimpleType_InT16
+ case vdl.Int32:
+ return mojom_types.SimpleType_InT32
+ case vdl.Int64:
+ return mojom_types.SimpleType_InT64
+ case vdl.Byte:
+ return mojom_types.SimpleType_UinT8
+ case vdl.Uint16:
+ return mojom_types.SimpleType_UinT16
+ case vdl.Uint32:
+ return mojom_types.SimpleType_UinT32
+ case vdl.Uint64:
+ return mojom_types.SimpleType_UinT64
+ default:
+ panic(fmt.Sprintf("kind %v does not represent a simple type", k))
+ }
+}
+
+func stringType(nullable bool) mojom_types.StringType {
+ return mojom_types.StringType{nullable}
+}
+
+func arrayType(elem mojom_types.Type, nullable bool, length int) mojom_types.ArrayType {
+ return mojom_types.ArrayType{nullable, int32(length), elem}
+}
+
+func listType(elem mojom_types.Type, nullable bool) mojom_types.ArrayType {
+ return mojom_types.ArrayType{nullable, -1, elem}
+}
+
+func mapType(key, value mojom_types.Type, nullable bool) mojom_types.MapType {
+ return mojom_types.MapType{nullable, key, value}
+}
+
+func structType(t *vdl.Type, mp map[string]mojom_types.UserDefinedType) mojom_types.UserDefinedType {
+ layout := computeStructLayout(t)
+ structFields := make([]mojom_types.StructField, t.NumField())
+ for i := 0; i < t.NumField(); i++ {
+ byteOffset, _ := layout.MojoOffsetsFromVdlIndex(i)
+ structFields[i] = mojom_types.StructField{
+ Type: vdlToMojomTypeInternal(t.Field(i).Type, false, mp),
+ Offset: int32(byteOffset),
+ }
+ }
+ return &mojom_types.UserDefinedTypeStructType{
+ mojom_types.MojomStruct{
+ Fields: structFields,
+ },
+ }
+}
+
+func unionType(t *vdl.Type, mp map[string]mojom_types.UserDefinedType) mojom_types.UserDefinedType {
+ unionFields := make([]mojom_types.UnionField, t.NumField())
+ for i := 0; i < t.NumField(); i++ {
+ unionFields[i] = mojom_types.UnionField{
+ Type: vdlToMojomTypeInternal(t.Field(i).Type, false, mp),
+ Tag: uint32(i),
+ }
+ }
+ return &mojom_types.UserDefinedTypeUnionType{
+ mojom_types.MojomUnion{
+ Fields: unionFields,
+ },
+ }
+}
+
+func enumType(t *vdl.Type) mojom_types.UserDefinedType {
+ enumValues := make([]mojom_types.EnumValue, t.NumEnumLabel())
+ for i := 0; i < t.NumEnumLabel(); i++ {
+ enumValues[i] = mojom_types.EnumValue{
+ EnumTypeKey: t.EnumLabel(i),
+ IntValue: int32(i),
+ }
+ }
+ return &mojom_types.UserDefinedTypeEnumType{
+ mojom_types.MojomEnum{
+ Values: enumValues,
+ },
+ }
+}
diff --git a/go/src/v.io/x/mojo/transcoder/type_test.go b/go/src/v.io/x/mojo/transcoder/type_test.go
new file mode 100644
index 0000000..56b3e0d
--- /dev/null
+++ b/go/src/v.io/x/mojo/transcoder/type_test.go
@@ -0,0 +1,164 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package transcoder_test
+
+import (
+ "mojo/public/interfaces/bindings/mojom_types"
+ "reflect"
+ "testing"
+
+ "v.io/v23/vdl"
+ "v.io/x/mojo/transcoder"
+)
+
+func TestVdlAndMojoTypeConversion(t *testing.T) {
+ // Create types.
+ /* Types are commented out pending the relevant tests being added.
+ enumType := vdl.NamedType("TestEnum", vdl.EnumType("A", "B", "C"))
+
+ basicStructType := vdl.NamedType("TestBasicStruct", vdl.StructType(vdl.Field{"TestEnum", enumType}, vdl.Field{"A", vdl.Int32Type}))
+
+ builder := vdl.TypeBuilder{}
+ strct := builder.Struct()
+ strct.AppendField("TestEnum", enumType)
+ namedStruct := builder.Named("TestStruct").AssignBase(strct)
+ strct.AppendField("TestStruct", builder.Optional().AssignElem(namedStruct))
+ strct.AppendField("A", vdl.Int32Type)
+ builder.Build()
+ cyclicStructType, err := namedStruct.Built()
+ if err != nil {
+ t.Fatalf("error building struct: %v", err)
+ }*/
+
+ tests := []struct {
+ vdl *vdl.Type
+ mojom mojom_types.Type
+ mp map[string]mojom_types.UserDefinedType
+ }{
+ {
+ vdl.BoolType,
+ &mojom_types.TypeSimpleType{mojom_types.SimpleType_Bool},
+ map[string]mojom_types.UserDefinedType{},
+ },
+ {
+ vdl.ByteType,
+ &mojom_types.TypeSimpleType{mojom_types.SimpleType_UinT8},
+ map[string]mojom_types.UserDefinedType{},
+ },
+ {
+ vdl.Uint16Type,
+ &mojom_types.TypeSimpleType{mojom_types.SimpleType_UinT16},
+ map[string]mojom_types.UserDefinedType{},
+ },
+ {
+ vdl.Uint32Type,
+ &mojom_types.TypeSimpleType{mojom_types.SimpleType_UinT32},
+ map[string]mojom_types.UserDefinedType{},
+ },
+ {
+ vdl.Uint64Type,
+ &mojom_types.TypeSimpleType{mojom_types.SimpleType_UinT64},
+ map[string]mojom_types.UserDefinedType{},
+ },
+ {
+ vdl.Int8Type,
+ &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT8},
+ map[string]mojom_types.UserDefinedType{},
+ },
+ {
+ vdl.Int16Type,
+ &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT16},
+ map[string]mojom_types.UserDefinedType{},
+ },
+ {
+ vdl.Int32Type,
+ &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT32},
+ map[string]mojom_types.UserDefinedType{},
+ },
+ {
+ vdl.Int64Type,
+ &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT64},
+ map[string]mojom_types.UserDefinedType{},
+ },
+ {
+ vdl.Float32Type,
+ &mojom_types.TypeSimpleType{mojom_types.SimpleType_Float},
+ map[string]mojom_types.UserDefinedType{},
+ },
+ {
+ vdl.Float64Type,
+ &mojom_types.TypeSimpleType{mojom_types.SimpleType_Double},
+ map[string]mojom_types.UserDefinedType{},
+ },
+ {
+ vdl.StringType,
+ &mojom_types.TypeStringType{mojom_types.StringType{false}},
+ map[string]mojom_types.UserDefinedType{},
+ },
+ // ?string is currently disallowed in vdl, so skipping
+ {
+ vdl.ArrayType(3, vdl.Int64Type),
+ &mojom_types.TypeArrayType{mojom_types.ArrayType{false, 3, &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT64}}},
+ map[string]mojom_types.UserDefinedType{},
+ },
+ // ?[3]int64 is currently disallowed in vdl, so skipping
+ {
+ vdl.ListType(vdl.Int64Type),
+ &mojom_types.TypeArrayType{mojom_types.ArrayType{false, -1, &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT64}}},
+ map[string]mojom_types.UserDefinedType{},
+ },
+ // ?[]int64 is currently disallowed in vdl, so skipping
+ {
+ vdl.MapType(vdl.Int64Type, vdl.BoolType),
+ &mojom_types.TypeMapType{mojom_types.MapType{false, &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT64}, &mojom_types.TypeSimpleType{mojom_types.SimpleType_Bool}}},
+ map[string]mojom_types.UserDefinedType{},
+ },
+ // ?map[int64]bool is currently disallowed in vdl, so skipping
+ /*
+ TODO(bprosnitz) We need a method to compare mojo types for equality
+ {
+ enumType,
+ &mojom_types.TypeTypeReference{mojom_types.TypeReference{Nullable: false, TypeKey: stringPtr("transcoder_testcases_TestEnum__")}},
+ map[string]mojom_types.UserDefinedType{
+ "transcoder_testcases_TestEnum__": transcoder_testcases.GetAllMojomTypeDefinitions()["transcoder_testcases_TestEnum__"],
+ },
+ },
+ {
+ basicStructType,
+ &mojom_types.TypeTypeReference{mojom_types.TypeReference{Nullable: false, TypeKey: stringPtr("transcoder_testcases_TestBasicStruct__")}},
+ map[string]mojom_types.UserDefinedType{
+ "transcoder_testcases_TestBasicStruct__": transcoder_testcases.GetAllMojomTypeDefinitions()["transcoder_testcases_TestBasicStruct__"],
+ "transcoder_testcases_TestEnum__": transcoder_testcases.GetAllMojomTypeDefinitions()["transcoder_testcases_TestEnum__"],
+ },
+ },
+ */
+ /* mojo -> vdl currently doesn't handle cycles
+ {
+ cyclicStructType,
+ &mojom_types.TypeTypeReference{mojom_types.TypeReference{Nullable: false, TypeKey: stringPtr("transcoder_testcases_TestCyclicStruct__")}},
+ map[string]mojom_types.UserDefinedType{
+ "transcoder_testcases_TestCyclicStruct__": transcoder_testcases.GetAllMojomTypeDefinitions()["transcoder_testcases_TestCyclicStruct__"],
+ "transcoder_testcases_TestEnum__": transcoder_testcases.GetAllMojomTypeDefinitions()["transcoder_testcases_TestEnum__"],
+ },
+ },
+ */
+ // TODO(bprosnitz) Are there any optional types in common between vdl and mojo?
+ }
+
+ for _, test := range tests {
+ mojomtype, mp := transcoder.VDLToMojomType(test.vdl)
+ if !reflect.DeepEqual(mojomtype, test.mojom) {
+ t.Errorf("vdl type %v, when converted to mojo type was %#v. expected %#v", test.vdl, mojomtype, test.mojom)
+ }
+ if !reflect.DeepEqual(mp, test.mp) {
+ t.Errorf("vdl type %v, when converted to mojo type did not match expected user defined types. got %#v, expected %#v", test.vdl, mojomtype, test.mojom)
+ }
+
+ vt := transcoder.MojomToVDLType(test.mojom, test.mp)
+ if !reflect.DeepEqual(vt, test.vdl) {
+ t.Errorf("mojom type %#v (with user defined types %v), when converted to vdl type was %v. expected %v", test.mojom, test.mp, vt, test.vdl)
+ }
+ }
+}
diff --git a/mojom/mojom/tests/transcoder_testcases.mojom b/mojom/mojom/tests/transcoder_testcases.mojom
index 9ac4b6b..9c7429c 100644
--- a/mojom/mojom/tests/transcoder_testcases.mojom
+++ b/mojom/mojom/tests/transcoder_testcases.mojom
@@ -38,3 +38,18 @@
struct ObjectUnionWrapper {
mojo.test.ObjectUnion object_union;
};
+
+enum TestEnum {
+ A, B, C
+};
+
+struct TestBasicStruct {
+ TestEnum TestEnum;
+ int32 a;
+};
+
+struct TestCyclicStruct {
+ TestEnum TestEnum;
+ TestCyclicStruct? TestCyclicStruct;
+ int32 a;
+};
\ No newline at end of file