func (t target) FromEnumLabel(src string, tt *vdl.Type) error { // enums in mojo are treated as an int32 on the wire (but have gaps in their values). // This implementation assumes that we will use generated VDL values and not have gaps. index := tt.EnumIndex(src) binary.LittleEndian.PutUint32(t.current.Bytes(), uint32(index)) return nil }
func neededStructAllocationSize(vt *vdl.Type) uint32 { var totalBits uint32 for fi := 0; fi < vt.NumField(); fi++ { field := vt.Field(fi) totalBits += baseTypeSizeBits(field.Type) } return roundBitsTo64Alignment(totalBits) }
func (t target) FromFloat(src float64, tt *vdl.Type) error { switch tt.Kind() { case vdl.Float32: binary.LittleEndian.PutUint32(t.current.Bytes(), math.Float32bits(float32(src))) case vdl.Float64: binary.LittleEndian.PutUint64(t.current.Bytes(), math.Float64bits(src)) default: return fmt.Errorf("invalid FromFloat(%v, %v)", src, tt) } return nil }
func (t target) FromInt(src int64, tt *vdl.Type) error { switch tt.Kind() { case vdl.Int8: t.current.Bytes()[0] = byte(src) case vdl.Int16: binary.LittleEndian.PutUint16(t.current.Bytes(), uint16(src)) case vdl.Int32: binary.LittleEndian.PutUint32(t.current.Bytes(), uint32(src)) case vdl.Int64: binary.LittleEndian.PutUint64(t.current.Bytes(), uint64(src)) default: return fmt.Errorf("invalid FromInt(%v, %v)", src, tt) } return nil }
func baseTypeSizeBits(vt *vdl.Type) uint32 { switch vt.Kind() { case vdl.Bool: return 1 case vdl.Byte, vdl.Int8: return 8 case vdl.Uint16, vdl.Int16: return 16 case vdl.Uint32, vdl.Int32, vdl.Float32, vdl.Enum: return 32 case vdl.Union: return 128 // Header + value / pointer to inner union default: // Either Uint64, Int64, Float64 or pointer. return 64 } }
// TODO(bprosnitz) This uses list, should we use map instead? func (t target) StartSet(tt *vdl.Type, len int) (vdl.SetTarget, error) { if tt.Kind() == vdl.Optional { tt = tt.Elem() } bitsNeeded := baseTypeSizeBits(tt.Key()) * uint32(len) block := t.allocator().Allocate((bitsNeeded+7)/8, uint32(len)) t.writePointer(block) if tt.Key().Kind() == vdl.Bool { return &bitListTarget{ block: block, }, nil } else { return &listTarget{ incrementSize: baseTypeSizeBits(tt.Key()) / 8, block: block, }, nil } }
func structType(t *vdl.Type, mp map[string]mojom_types.UserDefinedType) mojom_types.UserDefinedType { structFields := make([]mojom_types.StructField, t.NumField()) for i := 0; i < t.NumField(); i++ { structFields[i] = mojom_types.StructField{ DeclData: &mojom_types.DeclarationData{ShortName: strPtr(t.Field(i).Name)}, Type: vdlToMojomTypeInternal(t.Field(i).Type, false, false, mp), Offset: 0, // Despite the fact that we can calculated the offset, set it to zero to match the generator } } _, name := vdl.SplitIdent(t.Name()) return &mojom_types.UserDefinedTypeStructType{ mojom_types.MojomStruct{ DeclData: &mojom_types.DeclarationData{ ShortName: strPtr(name), FullIdentifier: strPtr(mojomIdentifier(t)), }, 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{ DeclData: &mojom_types.DeclarationData{ShortName: strPtr(t.Field(i).Name)}, Type: vdlToMojomTypeInternal(t.Field(i).Type, false, false, mp), Tag: uint32(i), } } _, name := vdl.SplitIdent(t.Name()) return &mojom_types.UserDefinedTypeUnionType{ mojom_types.MojomUnion{ DeclData: &mojom_types.DeclarationData{ ShortName: strPtr(name), FullIdentifier: strPtr(mojomIdentifier(t)), }, Fields: unionFields, }, } }
// computeStructLayout computes a representation of the fields in a struct, as // a list ordered by mojom byte field order. func computeStructLayout(t *vdl.Type) (layout structLayout) { a := structBitAllocation{} for i := 0; i < t.NumField(); i++ { bits := baseTypeSizeBits(t.Field(i).Type) a = allocateStructBits(a, i+1, int(bits)) } lastVal := 0 for i, v := range a { if v != lastVal && v != 0 { layout = append(layout, structLayoutField{ vdlStructIndex: v - 1, byteOffset: uint32(i / 8), bitOffset: uint8(i % 8), }) lastVal = v } } return }
func addUserDefinedType(t *vdl.Type, mp map[string]mojom_types.UserDefinedType) string { key := mojomTypeKey(t) 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 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{ DeclData: &mojom_types.DeclarationData{ShortName: strPtr(t.EnumLabel(i))}, IntValue: int32(i), } } _, name := vdl.SplitIdent(t.Name()) return &mojom_types.UserDefinedTypeEnumType{ mojom_types.MojomEnum{ DeclData: &mojom_types.DeclarationData{ ShortName: strPtr(name), FullIdentifier: strPtr(mojomIdentifier(t)), }, Values: enumValues, }, } }
func (t target) StartFields(tt *vdl.Type) (vdl.FieldsTarget, error) { if tt.Kind() == vdl.Optional { tt = tt.Elem() } if tt.Kind() == vdl.Union { return unionFieldsTarget{ vdlType: tt, block: t.current, }, nil } fieldsTarget, block, err := structFieldShared(tt, t.allocator(), true) t.writePointer(block) return fieldsTarget, err }
func (t target) StartMap(tt *vdl.Type, len int) (vdl.MapTarget, error) { if tt.Kind() == vdl.Optional { tt = tt.Elem() } pointerBlock := t.allocator().Allocate(16, 0) t.writePointer(pointerBlock) st := target{ current: pointerBlock.Slice(0, 8), } keys, err := st.StartSet(vdl.SetType(tt.Key()), len) if err != nil { return nil, err } valuePlaceholder := target{ current: pointerBlock.Slice(8, 16), } return &mapTarget{ keys: keys, valuePlaceholder: valuePlaceholder, valueType: tt.Elem(), }, nil }
func JoinRawBytesAsStruct(targ vdl.Target, structType *vdl.Type, fields []*vom.RawBytes) error { st, err := targ.StartFields(structType) if err != nil { return err } if structType.NumField() != len(fields) { return fmt.Errorf("received %d fields, but %v has %d fields", len(fields), structType, structType.NumField()) } for i := 0; i < structType.NumField(); i++ { f := structType.Field(i) k, t, err := st.StartField(f.Name) if err != nil { return err } if err := fields[i].FillVDLTarget(t, f.Type); err != nil { return err } if err := st.FinishField(k, t); err != nil { return err } } return targ.FinishFields(st) }
func mojomIdentifier(t *vdl.Type) string { return strings.Replace(t.Name(), "/", ".", -1) }
func (t target) fromZero(tt *vdl.Type) error { if tt.IsBytes() { return t.FromBytes(nil, tt) } switch tt.Kind() { case vdl.Optional: elemType := tt.Elem() switch elemType.Kind() { case vdl.Union, vdl.Struct: // Array? String? Bytes? List? Set? // Note: for union, this zeros 16 bytes, but for others it does just 8. zeroBytes(t.current.Bytes()) default: panic(fmt.Sprintf("Vdl type %v cannot be optional", tt)) } case vdl.Any: panic("Any rep not yet determined") case vdl.Bool: return t.FromBool(false, tt) case vdl.Byte, vdl.Uint16, vdl.Uint32, vdl.Uint64: return t.FromUint(0, tt) case vdl.Int8, vdl.Int16, vdl.Int32, vdl.Int64: return t.FromInt(0, tt) case vdl.Float32, vdl.Float64: return t.FromFloat(0, tt) case vdl.String: return t.FromString("", tt) case vdl.Enum: return t.FromEnumLabel(tt.EnumLabel(0), tt) case vdl.TypeObject: return t.FromTypeObject(vdl.AnyType) case vdl.List: lt, err := t.StartList(tt, 0) if err != nil { return err } return t.FinishList(lt) case vdl.Array: lt, err := t.StartList(tt, tt.Len()) if err != nil { return err } for i := 0; i < tt.Len(); i++ { targ, err := lt.StartElem(i) if err != nil { return err } if err := targ.(target).fromZero(tt.Elem()); err != nil { return err } if err := lt.FinishElem(targ); err != nil { return err } } return t.FinishList(lt) case vdl.Map: mt, err := t.StartMap(tt, 0) if err != nil { return err } return t.FinishMap(mt) case vdl.Set: st, err := t.StartSet(tt, 0) if err != nil { return err } return t.FinishSet(st) case vdl.Struct: st, err := t.StartFields(tt) if err != nil { return err } for i := 0; i < tt.NumField(); i++ { fld := tt.Field(i) kt, ft, err := st.StartField(fld.Name) if err != nil { return err } if err := ft.(target).fromZero(fld.Type); err != nil { return err } if err := st.FinishField(kt, ft); err != nil { return err } } return t.FinishFields(st) case vdl.Union: st, err := t.StartFields(tt) if err != nil { return err } fld := tt.Field(0) kt, ft, err := st.StartField(fld.Name) if err != nil { return err } if err := ft.(target).fromZero(fld.Type); err != nil { return err } if err := st.FinishField(kt, ft); err != nil { return err } return t.FinishFields(st) default: panic(fmt.Sprintf("unknown type %v", tt)) } return nil }
func vdlToMojomTypeInternal(t *vdl.Type, outermostType bool, 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()), } case vdl.String: return &mojom_types.TypeStringType{ stringType(nullable), } case vdl.Array: elem := vdlToMojomTypeInternal(t.Elem(), false, false, mp) return &mojom_types.TypeArrayType{ arrayType(elem, nullable, t.Len()), } case vdl.List: elem := vdlToMojomTypeInternal(t.Elem(), false, false, mp) return &mojom_types.TypeArrayType{ listType(elem, nullable), } case vdl.Map: key := vdlToMojomTypeInternal(t.Key(), false, false, mp) elem := vdlToMojomTypeInternal(t.Elem(), false, false, mp) return &mojom_types.TypeMapType{ mapType(key, elem, nullable), } case vdl.Struct, vdl.Union, vdl.Enum: udtKey := addUserDefinedType(t, mp) ret := &mojom_types.TypeTypeReference{ mojom_types.TypeReference{ Nullable: nullable, TypeKey: &udtKey, }, } if !outermostType { // This is needed to match the output of the generator exactly, the outermost type // is not given an identifier. ret.Value.Identifier = ret.Value.TypeKey } return ret case vdl.Optional: return vdlToMojomTypeInternal(t.Elem(), false, true, mp) default: panic(fmt.Sprintf("conversion from VDL kind %v to mojom type not implemented", t.Kind())) } }
func (targ *structSplitTarget) StartFields(tt *vdl.Type) (vdl.FieldsTarget, error) { targ.tt = tt targ.fields = make([]*vom.RawBytes, tt.NumField()) return &structSplitFieldsTarget{targ}, nil }
func (t target) FromNil(tt *vdl.Type) error { if tt.Kind() == vdl.Optional || tt.Kind() == vdl.Any { return t.fromZero(tt) } return fmt.Errorf("FromNil called on non-nillable type") }
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)) } }