| // 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 vdl |
| |
| import ( |
| "fmt" |
| "reflect" |
| ) |
| |
| // Target represents a generic conversion target; objects that implement this |
| // interface may be used as the target of a value conversion. E.g. |
| // ReflectTarget and ValueTarget create targets based on an underlying |
| // reflect.Value or Value respectively. Other implementations of this |
| // interface include vom encoding targets, that produce binary and JSON vom |
| // encodings. |
| type Target interface { |
| // FromBool converts from the src bool to the target, where tt represents the |
| // concrete type of bool. |
| FromBool(src bool, tt *Type) error |
| // FromUint converts from the src uint to the target, where tt represents the |
| // concrete type of uint. |
| FromUint(src uint64, tt *Type) error |
| // FromInt converts from the src int to the target, where tt represents the |
| // concrete type of int. |
| FromInt(src int64, tt *Type) error |
| // FromFloat converts from the src float to the target, where tt represents |
| // the concrete type of float. |
| FromFloat(src float64, tt *Type) error |
| // FromComplex converts from the src complex to the target, where tt |
| // represents the concrete type of complex. |
| FromComplex(src complex128, tt *Type) error |
| // FromBytes converts from the src bytes to the target, where tt represents |
| // the concrete type of bytes. |
| FromBytes(src []byte, tt *Type) error |
| // FromString converts from the src string to the target, where tt represents |
| // the concrete type of string. |
| FromString(src string, tt *Type) error |
| // FromEnumLabel converts from the src enum label to the target, where tt |
| // represents the concrete type of enum. |
| FromEnumLabel(src string, tt *Type) error |
| // FromTypeObject converts from the src type to the target. |
| FromTypeObject(src *Type) error |
| // FromNil converts from a nil (nonexistent) value of type tt, where tt must |
| // be of kind Optional or Any. |
| FromNil(tt *Type) error |
| |
| // StartList prepares conversion from a list or array of type tt, with the |
| // given len. FinishList must be called to finish the list. |
| StartList(tt *Type, len int) (ListTarget, error) |
| // FinishList finishes a prior StartList call. |
| FinishList(x ListTarget) error |
| |
| // StartSet prepares conversion from a set of type tt, with the given len. |
| // FinishSet must be called to finish the set. |
| StartSet(tt *Type, len int) (SetTarget, error) |
| // FinishSet finishes a prior StartSet call. |
| FinishSet(x SetTarget) error |
| |
| // StartMap prepares conversion from a map of type tt, with the given len. |
| // FinishMap must be called to finish the map. |
| StartMap(tt *Type, len int) (MapTarget, error) |
| // FinishMap finishes a prior StartMap call. |
| FinishMap(x MapTarget) error |
| |
| // StartFields prepares conversion from a struct or union of type tt. |
| // FinishFields must be called to finish the fields. |
| StartFields(tt *Type) (FieldsTarget, error) |
| // FinishFields finishes a prior StartFields call. |
| FinishFields(x FieldsTarget) error |
| } |
| |
| // ListTarget represents conversion from a list or array. |
| type ListTarget interface { |
| // StartElem prepares conversion of the next list elem. The given index must |
| // start at 0, and be incremented by one by each successive StartElem call. |
| // FinishElem must be called to finish the elem. |
| // |
| // TODO(toddw): Remove index? |
| StartElem(index int) (elem Target, _ error) |
| // FinishElem finishes a prior StartElem call. |
| FinishElem(elem Target) error |
| } |
| |
| // SetTarget represents conversion from a set. |
| type SetTarget interface { |
| // StartKey prepares conversion of the next set key. FinishKey must be called |
| // to finish the key. |
| StartKey() (key Target, _ error) |
| // FinishKey finishes a prior StartKey call. ErrFieldNoExist indicates the |
| // key doesn't exist on the target. |
| FinishKey(key Target) error |
| } |
| |
| // MapTarget represents conversion from a map. |
| type MapTarget interface { |
| // StartKey prepares conversion of the next map key. FinishKeyStartField must |
| // be called to finish the key. |
| StartKey() (key Target, _ error) |
| // FinishKeyStartField finishes a prior StartKey call, and starts the |
| // associated field. ErrFieldNoExist indicates the key doesn't exist on the |
| // target. |
| FinishKeyStartField(key Target) (field Target, _ error) |
| // FinishField finishes a prior FinishKeyStartField call. |
| FinishField(key, field Target) error |
| } |
| |
| // FieldsTarget represents conversion from struct or union fields. |
| type FieldsTarget interface { |
| // StartField prepares conversion of the field with the given name. |
| // FinishField must be called to finish the field. ErrFieldNoExist indicates |
| // the field name doesn't exist on the target. |
| StartField(name string) (key, field Target, _ error) |
| // FinishField finishes a prior StartField call. |
| FinishField(key, field Target) error |
| } |
| |
| // Convert converts from src to target - it is a helper for calling |
| // ReflectTarget(reflect.ValueOf(target)).FromReflect(reflect.ValueOf(src)). |
| func Convert(target, src interface{}) error { |
| rtarget, err := ReflectTarget(reflect.ValueOf(target)) |
| if err != nil { |
| return err |
| } |
| return FromReflect(rtarget, reflect.ValueOf(src)) |
| } |
| |
| // ValueOf returns the value corresponding to v. It's a helper for calling |
| // ValueFromReflect, and panics on any errors. |
| func ValueOf(v interface{}) *Value { |
| vv, err := ValueFromReflect(reflect.ValueOf(v)) |
| if err != nil { |
| panic(err) |
| } |
| return vv |
| } |
| |
| // ValueFromReflect returns the value corresponding to rv. |
| func ValueFromReflect(rv reflect.Value) (*Value, error) { |
| var result *Value |
| target, err := ReflectTarget(reflect.ValueOf(&result)) |
| if err != nil { |
| return nil, err |
| } |
| if err := FromReflect(target, rv); err != nil { |
| return nil, err |
| } |
| return result, nil |
| } |
| |
| // stringable exists to avoid a call to reflect.Call() to invoke String() |
| // which results in an allocation |
| type stringable interface { |
| String() string |
| } |
| |
| // nameable exists to avoid a call to reflect.Call() to invoke Name() |
| // which results in an allocation |
| type nameable interface { |
| Name() string |
| } |
| |
| // FromReflect converts from rv to the target, by walking through rv and calling |
| // the appropriate methods on the target. |
| func FromReflect(target Target, rv reflect.Value) error { |
| // Special-case to treat interface{}(nil) as any(nil). |
| if !rv.IsValid() { |
| return target.FromNil(AnyType) |
| } |
| // Flatten pointers and interfaces in rv, and handle special-cases. We track |
| // whether the final flattened value had any pointers via hasPtr, in order to |
| // track optional types correctly. |
| hasPtr := false |
| for rv.Kind() == reflect.Ptr || rv.Kind() == reflect.Interface { |
| // Handle special-case for errors. |
| if rv.Type().ConvertibleTo(rtError) && !rv.IsNil() { |
| return fromError(target, rv) |
| } |
| // Handle marshaling from native type to wire type. |
| if ni := nativeInfoFromNative(rv.Type()); ni != nil { |
| newWire := reflect.New(ni.WireType) |
| if err := ni.FromNative(newWire, rv); err != nil { |
| return err |
| } |
| if hasPtr { |
| return FromReflect(target, newWire) |
| } |
| return FromReflect(target, newWire.Elem()) |
| } |
| hasPtr = rv.Kind() == reflect.Ptr |
| switch rt := rv.Type(); { |
| case rv.IsNil(): |
| tt, err := TypeFromReflect(rv.Type()) |
| if err != nil { |
| return err |
| } |
| switch { |
| case tt.Kind() == TypeObject: |
| // Treat nil *Type as AnyType. |
| return target.FromTypeObject(AnyType) |
| case tt.Kind() == Union && rt.Kind() == reflect.Interface: |
| // Treat nil Union interface as the value of the type at index 0. |
| return FromValue(target, ZeroValue(tt)) |
| } |
| return target.FromNil(tt) |
| case rt.ConvertibleTo(rtPtrToType): |
| // If rv is convertible to *Type, fill from it directly. |
| return target.FromTypeObject(rv.Convert(rtPtrToType).Interface().(*Type)) |
| case rt.ConvertibleTo(rtPtrToValue): |
| // If rv is convertible to *Value, fill from it directly. |
| return FromValue(target, rv.Convert(rtPtrToValue).Interface().(*Value)) |
| } |
| rv = rv.Elem() |
| } |
| // Handle special-case for errors. |
| if rv.Type().ConvertibleTo(rtError) { |
| return fromError(target, rv) |
| } |
| // Handle marshaling from native type to wire type. |
| if ni := nativeInfoFromNative(rv.Type()); ni != nil { |
| newWire := reflect.New(ni.WireType) |
| if err := ni.FromNative(newWire, rv); err != nil { |
| return err |
| } |
| if hasPtr { |
| return FromReflect(target, newWire) |
| } |
| return FromReflect(target, newWire.Elem()) |
| } |
| // Initialize type information. The optionality is a bit tricky. Both rt and |
| // rv refer to the flattened value, with no pointers or interfaces. But tt |
| // refers to the optional type, iff the original value had a pointer. This is |
| // required so that each of the Target.From* methods can get full type |
| // information, including optionality. |
| rt := rv.Type() |
| tt, err := TypeFromReflect(rv.Type()) |
| if err != nil { |
| return err |
| } |
| ttFrom := tt |
| if tt.CanBeOptional() && hasPtr { |
| ttFrom = OptionalType(tt) |
| } |
| // Recursive walk through the reflect value to fill in target. |
| // |
| // First handle special-cases enum and union. Note that TypeFromReflect |
| // has already validated the methods, so we can call without error checking. |
| switch tt.Kind() { |
| case Enum: |
| label := rv.Interface().(stringable).String() |
| return target.FromEnumLabel(label, ttFrom) |
| case Union: |
| // We're guaranteed rv is the concrete field struct. |
| name := rv.Interface().(nameable).Name() |
| fieldsTarget, err := target.StartFields(ttFrom) |
| if err != nil { |
| return err |
| } |
| key, field, err := fieldsTarget.StartField(name) |
| if err != nil { |
| return err // no ErrFieldNoExist special-case; union field is required |
| } |
| // Grab the "Value" field of the concrete field struct. |
| rvFieldValue := rv.Field(0) |
| if err := FromReflect(field, rvFieldValue); err != nil { |
| return err |
| } |
| if err := fieldsTarget.FinishField(key, field); err != nil { |
| return err |
| } |
| return target.FinishFields(fieldsTarget) |
| } |
| // Now handle special-case bytes. |
| if isRTBytes(rt) { |
| return target.FromBytes(rtBytes(rv), ttFrom) |
| } |
| // Handle standard kinds. |
| switch rt.Kind() { |
| case reflect.Bool: |
| return target.FromBool(rv.Bool(), ttFrom) |
| case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr: |
| return target.FromUint(rv.Uint(), ttFrom) |
| case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: |
| return target.FromInt(rv.Int(), ttFrom) |
| case reflect.Float32, reflect.Float64: |
| return target.FromFloat(rv.Float(), ttFrom) |
| case reflect.Complex64, reflect.Complex128: |
| return target.FromComplex(rv.Complex(), ttFrom) |
| case reflect.String: |
| return target.FromString(rv.String(), ttFrom) |
| case reflect.Array, reflect.Slice: |
| listTarget, err := target.StartList(ttFrom, rv.Len()) |
| if err != nil { |
| return err |
| } |
| for ix := 0; ix < rv.Len(); ix++ { |
| elem, err := listTarget.StartElem(ix) |
| if err != nil { |
| return err |
| } |
| if err := FromReflect(elem, rv.Index(ix)); err != nil { |
| return err |
| } |
| if err := listTarget.FinishElem(elem); err != nil { |
| return err |
| } |
| } |
| return target.FinishList(listTarget) |
| case reflect.Map: |
| if tt.Kind() == Set { |
| setTarget, err := target.StartSet(ttFrom, rv.Len()) |
| if err != nil { |
| return err |
| } |
| for _, rvkey := range rv.MapKeys() { |
| key, err := setTarget.StartKey() |
| if err != nil { |
| return err |
| } |
| if err := FromReflect(key, rvkey); err != nil { |
| return err |
| } |
| switch err := setTarget.FinishKey(key); { |
| case err == ErrFieldNoExist: |
| continue // silently drop unknown fields |
| case err != nil: |
| return err |
| } |
| } |
| return target.FinishSet(setTarget) |
| } |
| mapTarget, err := target.StartMap(ttFrom, rv.Len()) |
| if err != nil { |
| return err |
| } |
| for _, rvkey := range rv.MapKeys() { |
| key, err := mapTarget.StartKey() |
| if err != nil { |
| return err |
| } |
| if err := FromReflect(key, rvkey); err != nil { |
| return err |
| } |
| field, err := mapTarget.FinishKeyStartField(key) |
| switch { |
| case err == ErrFieldNoExist: |
| continue // silently drop unknown fields |
| case err != nil: |
| return err |
| } |
| if err := FromReflect(field, rv.MapIndex(rvkey)); err != nil { |
| return err |
| } |
| if err := mapTarget.FinishField(key, field); err != nil { |
| return err |
| } |
| } |
| return target.FinishMap(mapTarget) |
| case reflect.Struct: |
| fieldsTarget, err := target.StartFields(ttFrom) |
| if err != nil { |
| return err |
| } |
| // Loop through tt fields rather than rt fields, since the VDL type tt might |
| // have ignored some of the fields in rt, e.g. unexported fields. |
| for fx := 0; fx < tt.NumField(); fx++ { |
| name := tt.Field(fx).Name |
| key, field, err := fieldsTarget.StartField(name) |
| switch { |
| case err == ErrFieldNoExist: |
| continue // silently drop unknown fields |
| case err != nil: |
| return err |
| } |
| rvField := rv.FieldByName(name) |
| if !rvField.IsValid() { |
| // This case occurs if the VDL type tt has a field name that doesn't |
| // eixst in the Go reflect.Type rt. This should never occur; it |
| // indicates a bug in the TypeOf logic. Panic here to give us a |
| // stack trace to make it easier to debug. |
| panic(fmt.Errorf("missing struct field %q, tt: %v, rt: %v", name, tt, rt)) |
| } |
| if err := FromReflect(field, rvField); err != nil { |
| return err |
| } |
| if err := fieldsTarget.FinishField(key, field); err != nil { |
| return err |
| } |
| } |
| return target.FinishFields(fieldsTarget) |
| default: |
| return fmt.Errorf("FromReflect invalid type %v", rt) |
| } |
| } |
| |
| // fromError handles all rv values that implement the error interface. |
| func fromError(target Target, rv reflect.Value) error { |
| // Convert to the WireError representation of rv. |
| ni, err := nativeInfoForError() |
| if err != nil { |
| return err |
| } |
| newWire := reflect.New(ni.WireType) |
| if err := ni.FromNative(newWire, rv); err != nil { |
| return err |
| } |
| // We know that rv is convertible to error; ensure we end up with the right |
| // optionality, in case target is an interface. |
| if rt := rv.Type(); rt.Kind() == reflect.Ptr && rt.Elem().ConvertibleTo(rtError) { |
| return FromReflect(target, newWire) |
| } |
| return FromReflect(target, newWire.Elem()) |
| } |
| |
| // FromValue converts from vv to the target, by walking through vv and calling |
| // the appropriate methods on the target. |
| func FromValue(target Target, vv *Value) error { |
| tt := vv.Type() |
| if tt.Kind() == Any { |
| if vv.IsNil() { |
| return target.FromNil(tt) |
| } |
| // Non-nil any simply converts from the elem. |
| vv = vv.Elem() |
| tt = vv.Type() |
| } |
| if tt.Kind() == Optional { |
| if vv.IsNil() { |
| return target.FromNil(tt) |
| } |
| // Non-nil optional is special - we keep tt as the optional type, but use |
| // the elem value for the actual value below. |
| vv = vv.Elem() |
| } |
| if vv.Type().IsBytes() { |
| return target.FromBytes(vv.Bytes(), tt) |
| } |
| switch vv.Kind() { |
| case Bool: |
| return target.FromBool(vv.Bool(), tt) |
| case Byte, Uint16, Uint32, Uint64: |
| return target.FromUint(vv.Uint(), tt) |
| case Int8, Int16, Int32, Int64: |
| return target.FromInt(vv.Int(), tt) |
| case Float32, Float64: |
| return target.FromFloat(vv.Float(), tt) |
| case Complex64, Complex128: |
| return target.FromComplex(vv.Complex(), tt) |
| case String: |
| return target.FromString(vv.RawString(), tt) |
| case Enum: |
| return target.FromEnumLabel(vv.EnumLabel(), tt) |
| case TypeObject: |
| return target.FromTypeObject(vv.TypeObject()) |
| case Array, List: |
| listTarget, err := target.StartList(tt, vv.Len()) |
| if err != nil { |
| return err |
| } |
| for ix := 0; ix < vv.Len(); ix++ { |
| elem, err := listTarget.StartElem(ix) |
| if err != nil { |
| return err |
| } |
| if err := FromValue(elem, vv.Index(ix)); err != nil { |
| return err |
| } |
| if err := listTarget.FinishElem(elem); err != nil { |
| return err |
| } |
| } |
| return target.FinishList(listTarget) |
| case Set: |
| setTarget, err := target.StartSet(tt, vv.Len()) |
| if err != nil { |
| return err |
| } |
| for _, vvkey := range vv.Keys() { |
| key, err := setTarget.StartKey() |
| if err != nil { |
| return err |
| } |
| if err := FromValue(key, vvkey); err != nil { |
| return err |
| } |
| switch err := setTarget.FinishKey(key); { |
| case err == ErrFieldNoExist: |
| continue // silently drop unknown fields |
| case err != nil: |
| return err |
| } |
| } |
| return target.FinishSet(setTarget) |
| case Map: |
| mapTarget, err := target.StartMap(tt, vv.Len()) |
| if err != nil { |
| return err |
| } |
| for _, vvkey := range vv.Keys() { |
| key, err := mapTarget.StartKey() |
| if err != nil { |
| return err |
| } |
| if err := FromValue(key, vvkey); err != nil { |
| return err |
| } |
| field, err := mapTarget.FinishKeyStartField(key) |
| switch { |
| case err == ErrFieldNoExist: |
| continue // silently drop unknown fields |
| case err != nil: |
| return err |
| } |
| if err := FromValue(field, vv.MapIndex(vvkey)); err != nil { |
| return err |
| } |
| if err := mapTarget.FinishField(key, field); err != nil { |
| return err |
| } |
| } |
| return target.FinishMap(mapTarget) |
| case Struct: |
| fieldsTarget, err := target.StartFields(tt) |
| if err != nil { |
| return err |
| } |
| for fx := 0; fx < vv.Type().NumField(); fx++ { |
| key, field, err := fieldsTarget.StartField(vv.Type().Field(fx).Name) |
| switch { |
| case err == ErrFieldNoExist: |
| continue // silently drop unknown fields |
| case err != nil: |
| return err |
| } |
| if err := FromValue(field, vv.StructField(fx)); err != nil { |
| return err |
| } |
| if err := fieldsTarget.FinishField(key, field); err != nil { |
| return err |
| } |
| } |
| return target.FinishFields(fieldsTarget) |
| case Union: |
| fieldsTarget, err := target.StartFields(tt) |
| if err != nil { |
| return err |
| } |
| fx, vvFieldValue := vv.UnionField() |
| key, field, err := fieldsTarget.StartField(vv.Type().Field(fx).Name) |
| if err != nil { |
| return err // no ErrFieldNoExist special-case; union field is required |
| } |
| if err := FromValue(field, vvFieldValue); err != nil { |
| return err |
| } |
| if err := fieldsTarget.FinishField(key, field); err != nil { |
| return err |
| } |
| return target.FinishFields(fieldsTarget) |
| default: |
| panic(fmt.Errorf("FromValue unhandled %v %v", vv.Kind(), tt)) |
| } |
| } |