func (t target) FinishMap(x vdl.MapTarget) error { mt := x.(*mapTarget) listTarget, err := mt.valuePlaceholder.StartList(vdl.ListType(mt.valueType), len(mt.cachedValues)) if err != nil { return err } for i, val := range mt.cachedValues { te, err := listTarget.StartElem(i) if err != nil { return err } if err := vdl.FromValue(te, val); err != nil { return err } if err := listTarget.FinishElem(te); err != nil { return err } } return nil }
func (mtv *mojomToTargetTranscoder) transcodeValue(vt *vdl.Type, target vdl.Target, isTopType, isNullable bool) error { switch vt.Kind() { case vdl.Bool: value, err := mtv.modec.ReadBool() if err != nil { return err } return target.FromBool(value, vt) case vdl.Int8: value, err := mtv.modec.ReadInt8() if err != nil { return err } return target.FromInt(int64(value), vt) case vdl.Int16: value, err := mtv.modec.ReadInt16() if err != nil { return err } return target.FromInt(int64(value), vt) case vdl.Int32: value, err := mtv.modec.ReadInt32() if err != nil { return err } return target.FromInt(int64(value), vt) case vdl.Int64: value, err := mtv.modec.ReadInt64() if err != nil { return err } return target.FromInt(value, vt) case vdl.Byte: value, err := mtv.modec.ReadUint8() if err != nil { return err } return target.FromUint(uint64(value), vt) case vdl.Uint16: value, err := mtv.modec.ReadUint16() if err != nil { return err } return target.FromUint(uint64(value), vt) case vdl.Uint32: value, err := mtv.modec.ReadUint32() if err != nil { return err } return target.FromUint(uint64(value), vt) case vdl.Uint64: value, err := mtv.modec.ReadUint64() if err != nil { return err } return target.FromUint(value, vt) case vdl.Float32: value, err := mtv.modec.ReadFloat32() if err != nil { return err } return target.FromFloat(float64(value), vt) case vdl.Float64: value, err := mtv.modec.ReadFloat64() if err != nil { return err } return target.FromFloat(value, vt) case vdl.String: switch ptr, err := mtv.modec.ReadPointer(); { case err != nil: return err case ptr == 0: return fmt.Errorf("invalid null string pointer") default: value, err := mtv.modec.ReadString() if err != nil { return err } return target.FromString(value, vt) } return nil case vdl.Enum: index, err := mtv.modec.ReadInt32() if err != nil { return err } if int(index) >= vt.NumEnumLabel() || index < 0 { return fmt.Errorf("enum label out of range") } target.FromEnumLabel(vt.EnumLabel(int(index)), vt) return nil case vdl.Array, vdl.List: switch ptr, err := mtv.modec.ReadPointer(); { case err != nil: return err case ptr == 0 && isNullable: return target.FromNil(vdl.OptionalType(vt)) case ptr == 0 && !isNullable: return fmt.Errorf("invalid null struct pointer") } if vt.IsBytes() { str, err := mtv.modec.ReadString() if err != nil { return err } return target.FromBytes([]byte(str), vt) } else { elemBitSize := baseTypeSizeBits(vt.Elem()) numElems, err := mtv.modec.StartArray(elemBitSize) if err != nil { return err } listTarget, err := target.StartList(vt, int(numElems)) if err != nil { return err } for i := 0; i < int(numElems); i++ { elemTarget, err := listTarget.StartElem(i) if err != nil { return err } if err := mtv.transcodeValue(vt.Elem(), elemTarget, false, false); err != nil { return err } if err := listTarget.FinishElem(elemTarget); err != nil { return err } } if err := target.FinishList(listTarget); err != nil { return err } } return mtv.modec.Finish() case vdl.Set: panic("unimplemented") /*switch ptr, err := d.dec.ReadPointer(); { case err != nil: return err case ptr == 0 && isNullable: return target.FromNil(vdl.OptionalType(vt)) case ptr == 0 && !isNullable: return fmt.Errorf("invalid null struct pointer") } keyBitSize := baseTypeSizeBits(vt.Key()) numKeys, err := d.dec.StartArray(keyBitSize) if err != nil { return err } setTarget, err := target.StartSet(vt, int(numKeys)) if err != nil { return err } for i := 0; i < int(numKeys); i++ { keyTarget, err := setTarget.StartKey() if err != nil { return err } if err := d.decodeValue(mt.Key, keyTarget, false, false); err != nil { return err } if err := setTarget.FinishKey(keyTarget); err != nil { return err } } if err := target.FinishSet(setTarget); err != nil { return err } return d.dec.Finish()*/ case vdl.Map: switch ptr, err := mtv.modec.ReadPointer(); { case err != nil: return err case ptr == 0 && isNullable: return target.FromNil(vdl.OptionalType(vt)) case ptr == 0 && !isNullable: return fmt.Errorf("invalid null struct pointer") } if err := mtv.modec.StartMap(); err != nil { return err } var keys, values []*vdl.Value keysTarget, err := vdl.ReflectTarget(reflect.ValueOf(&keys)) if err != nil { return err } keysListType := vdl.ListType(vt.Key()) if err := mtv.transcodeValue(keysListType, keysTarget, false, false); err != nil { return err } valuesTarget, err := vdl.ReflectTarget(reflect.ValueOf(&values)) if err != nil { return err } valuesListType := vdl.ListType(vt.Elem()) if err := mtv.transcodeValue(valuesListType, valuesTarget, false, false); err != nil { return err } if len(keys) != len(values) { return fmt.Errorf("values don't match keys") } mapTarget, err := target.StartMap(vt, len(keys)) if err != nil { return err } for i, key := range keys { value := values[i] keyTarget, err := mapTarget.StartKey() if err != nil { return err } if err := vdl.FromValue(keyTarget, key); err != nil { return err } fieldTarget, err := mapTarget.FinishKeyStartField(keyTarget) if err != nil { return err } if err := vdl.FromValue(fieldTarget, value); err != nil { return err } if err := mapTarget.FinishField(keyTarget, fieldTarget); err != nil { return err } } if err := target.FinishMap(mapTarget); err != nil { return err } return mtv.modec.Finish() case vdl.Struct: // TODO(toddw): See the comment in encoder.mojomStructSize; we rely on the // fields to be presented in the canonical mojom field ordering. if !isTopType { switch ptr, err := mtv.modec.ReadPointer(); { case err != nil: return err case ptr == 0 && isNullable: return target.FromNil(vdl.OptionalType(vt)) case ptr == 0 && !isNullable: return fmt.Errorf("invalid null struct pointer") } } _, err := mtv.modec.StartStruct() if err != nil { return err } targetFields, err := target.StartFields(vt) if err != nil { return err } for _, alloc := range computeStructLayout(vt) { mfield := vt.Field(alloc.vdlStructIndex) switch vkey, vfield, err := targetFields.StartField(mfield.Name); { // TODO(toddw): Handle err == vdl.ErrFieldNoExist case? case err != nil: return err default: if err := mtv.transcodeValue(mfield.Type, vfield, false, false); err != nil { return err } if err := targetFields.FinishField(vkey, vfield); err != nil { return err } } } // TODO(toddw): Fill in fields that weren't decoded with their zero value. if err := target.FinishFields(targetFields); err != nil { return err } return mtv.modec.Finish() case vdl.Union: size, tag, err := mtv.modec.ReadUnionHeader() if err != nil { return err } if size == 0 { mtv.modec.SkipUnionValue() return target.FromNil(vdl.OptionalType(vt)) } if int(tag) >= vt.NumField() { return fmt.Errorf("union tag out of bounds") } fld := vt.Field(int(tag)) targetFields, err := target.StartFields(vt) if err != nil { return err } vKey, vField, err := targetFields.StartField(fld.Name) if err != nil { return err } if fld.Type.Kind() == vdl.Union { switch ptr, err := mtv.modec.ReadPointer(); { case err != nil: return err case ptr == 0 && isNullable: return target.FromNil(vdl.OptionalType(fld.Type)) case ptr == 0 && !isNullable: return fmt.Errorf("invalid null union pointer") } if err := mtv.modec.StartNestedUnion(); err != nil { return err } } if err := mtv.transcodeValue(fld.Type, vField, false, false); err != nil { return err } if fld.Type.Kind() == vdl.Union { if err := mtv.modec.Finish(); err != nil { return err } } if err := targetFields.FinishField(vKey, vField); err != nil { return err } if err := target.FinishFields(targetFields); err != nil { return err } mtv.modec.FinishReadingUnionValue() return nil case vdl.Optional: return mtv.transcodeValue(vt.Elem(), target, false, true) case vdl.Any: panic("unimplemented") //case vdl.TypeObject: // panic("unimplemented") default: panic(fmt.Errorf("decodeValue unhandled vdl type: %v", vt)) } }
func TestVdlAndMojoTypeConversion(t *testing.T) { // Create types. enumType := vdl.NamedType("v23proxy/tests/transcoder_testcases.TestEnum", vdl.EnumType("A", "B", "C")) basicStructType := vdl.NamedType("v23proxy/tests/transcoder_testcases.TestBasicStruct", vdl.StructType(vdl.Field{"Enum", enumType}, vdl.Field{"A", vdl.Int32Type})) builder := vdl.TypeBuilder{} strct := builder.Struct() strct.AppendField("Enum", enumType) namedStruct := builder.Named("v23proxy/tests/transcoder_testcases.TestCyclicStruct").AssignBase(strct) strct.AppendField("CyclicStruct", 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 { enumType, &mojom_types.TypeTypeReference{mojom_types.TypeReference{Nullable: false, TypeKey: stringPtr("TYPE_KEY:v23proxy.tests.transcoder_testcases.TestEnum")}}, map[string]mojom_types.UserDefinedType{ "TYPE_KEY:v23proxy.tests.transcoder_testcases.TestEnum": transcoder_testcases.GetAllMojomTypeDefinitions()["TYPE_KEY:v23proxy.tests.transcoder_testcases.TestEnum"], }, }, { basicStructType, &mojom_types.TypeTypeReference{mojom_types.TypeReference{Nullable: false, TypeKey: stringPtr("TYPE_KEY:v23proxy.tests.transcoder_testcases.TestBasicStruct")}}, map[string]mojom_types.UserDefinedType{ "TYPE_KEY:v23proxy.tests.transcoder_testcases.TestBasicStruct": transcoder_testcases.GetAllMojomTypeDefinitions()["TYPE_KEY:v23proxy.tests.transcoder_testcases.TestBasicStruct"], "TYPE_KEY:v23proxy.tests.transcoder_testcases.TestEnum": transcoder_testcases.GetAllMojomTypeDefinitions()["TYPE_KEY:v23proxy.tests.transcoder_testcases.TestEnum"], }, }, { cyclicStructType, &mojom_types.TypeTypeReference{mojom_types.TypeReference{Nullable: false, TypeKey: stringPtr("TYPE_KEY:v23proxy.tests.transcoder_testcases.TestCyclicStruct")}}, map[string]mojom_types.UserDefinedType{ "TYPE_KEY:v23proxy.tests.transcoder_testcases.TestCyclicStruct": transcoder_testcases.GetAllMojomTypeDefinitions()["TYPE_KEY:v23proxy.tests.transcoder_testcases.TestCyclicStruct"], "TYPE_KEY:v23proxy.tests.transcoder_testcases.TestEnum": transcoder_testcases.GetAllMojomTypeDefinitions()["TYPE_KEY:v23proxy.tests.transcoder_testcases.TestEnum"], }, }, } for _, test := range tests { mojomtype, mp := transcoder.VDLToMojomType(test.vdl) // Note: Equality is only guaranteed if the casing matches up. Mojom no longer sends out UpperCamelCase values. 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) } // Note: Equality of structs is virtually impossible. The DeclarationData of the values in the map contains lots of information we cannot recover from vdl. //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, mp, test.mp) //} for k, _ := range test.mp { if _, ok := mp[k]; !ok { t.Errorf("vdl type %v, when converted to mojo type did not create an entry for %s", test.vdl, k) } } if len(mp) != len(test.mp) { t.Errorf("vdl type %v, when converted to mojo type created %d map entries, expected %d", test.vdl, len(mp), len(test.mp)) } vt, err := transcoder.MojomToVDLType(test.mojom, test.mp) if err != nil { t.Errorf("error converting mojo type %#v (with user defined types %v): %v", test.mojom, test.mp, err) } 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) } } }