blob: d9582573c273e8c5fbf0786f7078cbd06573edf1 [file] [log] [blame]
// 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
// Naming conventions to distinguish this package from reflect:
// tt - refers to *Type
// vv - refers to *Value
// rt - refers to reflect.Type
// rv - refers to reflect.Value
import (
"errors"
"fmt"
"reflect"
)
var (
ErrFieldNoExist = errors.New("field doesn't exist")
errTargetInvalid = errors.New("invalid target")
errTargetUnsettable = errors.New("unsettable target")
errArrayIndex = errors.New("array index out of range")
)
// convTarget represents the state and logic for value conversion.
//
// TODO(toddw): Split convTarget apart into reflectTarget and valueTarget.
type convTarget struct {
// Conceptually this is a disjoint union between the two types of destination
// values: *Value and reflect.Value. Only one of the vv and rv fields is
// ever valid. We split into two fields and perform "if vv == nil" checks in
// each method rather than using an interface for performance reasons.
//
// The tt field is always non-nil, and represents the type of the value.
tt *Type
vv *Value
rv reflect.Value
}
// ReflectTarget returns a conversion Target based on the given reflect.Value.
// Some rules depending on the type of rv:
// o If rv is a valid *Value, it is filled in directly.
// o Otherwise rv must be a settable value (i.e. it must be a pointer).
// o Pointers are followed, and logically "flattened".
// o New values are automatically created for nil pointers.
// o Targets convertible to *Type and *Value are filled in directly.
func ReflectTarget(rv reflect.Value) (Target, error) {
if !rv.IsValid() {
return nil, errTargetInvalid
}
if vv := extractValue(rv); vv.IsValid() {
return valueConv(vv), nil
}
if !rv.CanSet() && rv.Kind() == reflect.Ptr && !rv.IsNil() {
// Dereference the pointer a single time to make rv settable.
rv = rv.Elem()
}
tt, err := TypeFromReflect(rv.Type())
if err != nil {
return nil, err
}
target, err := reflectConv(rv, tt)
if err != nil {
return nil, err
}
return target, nil
}
// ValueTarget returns a conversion Target based on the given Value.
// Returns an error if the given Value isn't valid.
func ValueTarget(vv *Value) (Target, error) {
if !vv.IsValid() {
return nil, errTargetInvalid
}
return valueConv(vv), nil
}
func reflectConv(rv reflect.Value, tt *Type) (convTarget, error) {
if !rv.IsValid() {
return convTarget{}, errTargetInvalid
}
if vv := extractValue(rv); vv.IsValid() {
return valueConv(vv), nil
}
if !rv.CanSet() {
return convTarget{}, errTargetUnsettable
}
return convTarget{tt: tt, rv: rv}, nil
}
func valueConv(vv *Value) convTarget {
return convTarget{tt: vv.Type(), vv: vv}
}
func extractValue(rv reflect.Value) *Value {
for rv.Kind() == reflect.Ptr && !rv.IsNil() {
if rv.Type().ConvertibleTo(rtPtrToValue) {
return rv.Convert(rtPtrToValue).Interface().(*Value)
}
rv = rv.Elem()
}
return nil
}
// startConvert prepares to fill in c, converting from type ttFrom. Returns fin
// and fill which are used by finishConvert to finish the conversion; fin
// represents the final target to assign to, and fill represents the target to
// actually fill in.
func startConvert(c convTarget, ttFrom *Type) (fin, fill convTarget, err error) {
if ttFrom.Kind() == Any {
return convTarget{}, convTarget{}, fmt.Errorf("can't convert from type %q - either call target.FromNil or target.From* for the element value", ttFrom)
}
if !compatible(c.tt, ttFrom) {
return convTarget{}, convTarget{}, fmt.Errorf("types %q and %q aren't compatible", c.tt, ttFrom)
}
fin = createFinTarget(c, ttFrom)
fill, err = createFillTarget(fin, ttFrom)
if err != nil {
return convTarget{}, convTarget{}, err
}
return fin, fill, nil
}
// setZeroVDLValue checks whether rv is convertible to *Value, and if so,
// sets rv to the zero value of ttFrom, returning the resulting value.
func setZeroVDLValue(rv reflect.Value, ttFrom *Type) *Value {
if rv.Type().ConvertibleTo(rtPtrToValue) {
vv := rv.Convert(rtPtrToValue).Interface().(*Value)
if !vv.IsValid() {
vv = ZeroValue(ttFrom)
rv.Set(reflect.ValueOf(vv).Convert(rv.Type()))
}
return vv
}
return nil
}
// createFinTarget returns the fin target for the conversion, flattening
// pointers and creating new non-nil values as necessary.
func createFinTarget(c convTarget, ttFrom *Type) convTarget {
if c.vv == nil {
// Create new pointers down to the final non-pointer value.
for c.rv.Kind() == reflect.Ptr {
// Handle case where rv is *Value; fill it in directly.
if vv := setZeroVDLValue(c.rv, ttFrom); vv.IsValid() {
if vv.Kind() == Optional {
vv.Assign(NonNilZeroValue(vv.Type()))
return convTarget{tt: ttFrom, vv: vv.Elem()}
}
return convTarget{tt: ttFrom, vv: vv}
}
// Set nil pointers to new pointers.
if c.rv.IsNil() {
c.rv.Set(reflect.New(c.rv.Type().Elem()))
}
// Stop at *Type to allow TypeObject values to be assigned.
if c.rv.Type().Elem() == rtType {
return c
}
c.rv = c.rv.Elem()
}
if c.tt.Kind() == Optional {
c.tt = c.tt.Elem() // flatten c.tt to match c.rv
}
} else {
// Create a non-nil value for optional types.
if c.tt.Kind() == Optional {
c.vv.Assign(NonNilZeroValue(c.tt))
c.tt, c.vv = c.tt.Elem(), c.vv.Elem()
}
}
return c
}
// createFillTarget returns the fill target for the conversion, creating new
// values of the appropriate type if necessary. The fill target must be a
// concrete type; if fin has type interface/any, we'll create a concrete type,
// and finishConvert will assign fin from the fill target. The type we choose
// to create is either a special-case (error or union), or based on the ttFrom
// type we're converting *from*.
//
// If fin is already a concrete type it's used directly as the fill target.
//
// There is one particularly weird trick that we need to use when the conversion
// target (i.e. fin) is a reflect union interface. The problem is that
// createFillTarget is called before we know which union field is set, so
// there's no way to create a concrete union struct representing the appropriate
// field. So we return a vdl.Value as the fill target, to capture the value.
// We still want the concrete union struct to be created at the end of the
// conversion, so we call makeReflectUnion in finishConvert to convert the
// vdl.Value back into a concrete union struct, which needs to work even if the
// type hasn't been registered.
//
// The comments below refer to this trick as the UNION TRICK.
//
// TODO(toddw): The UNION TRICK is probably very slow. We should benchmark and
// probably re-design our conversion strategy.
//
// TODO(toddw): The conversion logic is way too complicated, with many similar
// branches; rewrite this entire file..
func createFillTarget(fin convTarget, ttFrom *Type) (convTarget, error) {
if fin.vv == nil {
// Handle case where fin.rv is the native error type; create the standard
// WireError struct to fill in.
if ni, err := nativeInfoForError(); err == nil && fin.rv.Type() == ni.NativeType {
return reflectConv(reflect.New(rtWireError).Elem(), ErrorType.Elem())
}
// Handle case where fin.rv is a native type; return the wire type as the
// fill target, and rely on finishConvert to perform the final step of
// converting from the wire type to the native type.
//
// TODO(toddw): This doesn't handle pointer native types.
if ni := nativeInfoFromNative(fin.rv.Type()); ni != nil {
tt, err := TypeFromReflect(ni.WireType)
if err != nil {
return convTarget{}, err
}
if tt.Kind() == Union {
// The wire type is a union. Apply the UNION TRICK (see above), and
// fill *Value, since we don't know which field is set.
return valueConv(ZeroValue(tt)), nil
}
return reflectConv(reflect.New(ni.WireType).Elem(), tt)
}
if fin.rv.Kind() == reflect.Interface {
// We're converting into an interface, so we can't just fill into the fin
// target directly. Return the appropriate fill value.
switch {
case fin.rv.Type() == rtError || ttFrom == ErrorType:
// Create the standard WireError struct to fill in, with the pointer.
return reflectConv(reflect.New(rtWireError).Elem(), ErrorType)
case ttFrom == ErrorType.Elem():
// Create the standard WireError struct to fill in, without the pointer.
return reflectConv(reflect.New(rtWireError).Elem(), ErrorType.Elem())
case fin.tt.Kind() == Union:
// The fin target is a union interface. Apply the UNION TRICK (see
// above), and fill *Value, since we don't know which field is set.
return valueConv(ZeroValue(fin.tt)), nil
case fin.tt.Kind() != Any:
return convTarget{}, fmt.Errorf("internal error - cannot convert to Go type %v vdl type %v from %v", fin.rv.Type(), fin.tt, ttFrom)
}
// We're converting into any, and ttFrom is the type we're converting
// *from*. First handle the special-case *Type.
if ttFrom.Kind() == TypeObject {
return reflectConv(reflect.New(rtPtrToType).Elem(), TypeObjectType)
}
// Try to create a reflect.Type out of ttFrom, and if it exists, create a real
// object to fill in.
if rt := TypeToReflect(ttFrom); rt != nil {
if rt.Kind() == reflect.Ptr && ttFrom.Kind() == Optional {
rt = rt.Elem()
}
// Handle case where rt is a native type; return the wire type as the
// fill target, and rely on finishConvert to perform the final step of
// converting from the wire type to the native type.
if ni := nativeInfoFromNative(rt); ni != nil {
if ttFrom.Kind() == Union {
// The wire type is a union interface. Apply the UNION TRICK (see
// above), and fill *Value, since we don't know which field is set.
return valueConv(ZeroValue(ttFrom)), nil
}
return reflectConv(reflect.New(ni.WireType).Elem(), ttFrom)
}
if rt.Kind() == reflect.Interface && ttFrom.Kind() == Union {
// The wire type is a union interface. Apply the UNION TRICK (see
// above), and fill *Value, since we don't know which field is set.
return valueConv(ZeroValue(ttFrom)), nil
}
rv := reflect.New(rt).Elem()
for rv.Kind() == reflect.Ptr {
rv.Set(reflect.New(rv.Type().Elem()))
rv = rv.Elem()
}
return reflectConv(rv, ttFrom)
}
// We don't have the type name in our registry, so create a concrete
// *Value to fill in, based on ttFrom.
if ttFrom.Kind() == Optional {
return convTarget{tt: ttFrom, vv: ZeroValue(ttFrom.Elem())}, nil
}
return convTarget{tt: ttFrom, vv: ZeroValue(ttFrom)}, nil
}
// We're not converting into an interface, so we can fill into the fin
// target directly. Assign an appropriate zero value.
fin.rv.Set(rvSettableZeroValue(fin.rv.Type(), ttFrom))
} else {
switch fin.vv.Kind() {
case Any:
if ttFrom.Kind() == Optional {
return convTarget{tt: ttFrom, vv: ZeroValue(ttFrom.Elem())}, nil
}
return convTarget{tt: ttFrom, vv: ZeroValue(ttFrom)}, nil
default:
fin.vv.Assign(nil) // start with zero item
}
}
return fin, nil
}
// finishConvert finishes converting a value, taking the fin and fill returned
// by startConvert. This is necessary since interface/any values are assigned
// by value, and can't be filled in by reference.
func finishConvert(fin, fill convTarget) error {
// The logic here mirrors the logic in createFillTarget.
if fin.vv == nil {
// Handle mirrored case in createFillTarget where fin.rv is the native error
// type; fill.rv is WireError.
if ni, err := nativeInfoForError(); err == nil && fin.rv.Type() == ni.NativeType {
return ni.ToNative(fill.rv, fin.rv.Addr())
}
// Handle mirrored case in createFillTarget where fin.rv is a native type;
// fill.rv is the wire type that has been filled in.
if ni := nativeInfoFromNative(fin.rv.Type()); ni != nil {
tt, err := TypeFromReflect(ni.WireType)
if err != nil {
return err
}
rvFill := fill.rv
if tt.Kind() == Union {
// If the fill target is a union type, finish conversion for the UNION
// TRICK (see above), to turn it into a concrete field struct.
if rvFill, err = makeReflectUnion(ni.WireType, fill.vv); err != nil {
return err
}
}
return ni.ToNative(rvFill, fin.rv.Addr())
}
if fin.rv.Kind() == reflect.Interface {
// The fill value may be set to either rv or vv in startConvert above.
var rvFill reflect.Value
if fill.vv == nil {
rvFill = fill.rv
if fill.rv.Type() == rtWireError {
// Handle case where fill.rv has type WireError; if error conversions
// have been registered with the vdl package, we need to convert to
// the standard error interface.
if ni, err := nativeInfoForError(); err == nil {
newNative := reflect.New(ni.NativeType)
if err := ni.ToNative(fill.rv, newNative); err != nil {
return err
}
rvFill = newNative.Elem()
}
} else if ni := nativeInfoFromWire(fill.rv.Type()); ni != nil {
// Handle case where fill.rv is a wire type with a native type; set
// rvFill to a new native type and call ToNative to fill it in.
newNative := reflect.New(ni.NativeType)
if err := ni.ToNative(fill.rv, newNative); err != nil {
return err
}
rvFill = newNative.Elem()
}
if fill.tt.Kind() == Optional {
// Convert rvFill into a pointer if it should be optional.
if rvFill.CanAddr() {
rvFill = rvFill.Addr()
} else {
rvNew := reflect.New(rvFill.Type())
rvNew.Elem().Set(rvFill)
rvFill = rvNew
}
}
} else {
// If the fill target is a union type, finish conversion for the UNION
// TRICK (see above), to turn it into a concrete field struct.
if fill.tt.Kind() == Union {
var err error
rvFill, err = makeReflectUnion(fin.rv.Type(), fill.vv)
if err != nil {
// Handle case where fin.rv is a native type; fill.vv is the union
// wire type that has been filled in.
if rt := TypeToReflect(fill.tt); rt != nil {
if ni := nativeInfoFromNative(rt); ni != nil {
rvWireUnion, err := makeReflectUnion(ni.WireType, fill.vv)
if err != nil {
return err
}
newNative := reflect.New(ni.NativeType)
if err := ni.ToNative(rvWireUnion, newNative); err != nil {
return err
}
rvFill = newNative.Elem()
}
}
}
}
if !rvFill.IsValid() {
switch fill.tt.Kind() {
case Optional:
rvFill = reflect.ValueOf(OptionalValue(fill.vv))
default:
rvFill = reflect.ValueOf(fill.vv)
}
}
}
if to, from := fin.rv.Type(), rvFill.Type(); !from.AssignableTo(to) {
return fmt.Errorf("%v not assignable from %v", to, from)
}
fin.rv.Set(rvFill)
}
} else {
switch fin.vv.Kind() {
case Any:
if fill.tt.Kind() == Optional {
fin.vv.Assign(OptionalValue(fill.vv))
} else {
fin.vv.Assign(fill.vv)
}
}
}
return nil
}
// rvSettableZeroValue returns a settable zero value corresponding to rt / tt.
// This isn't trivial since VDL and Go define zero values slightly differently.
// In particular in VDL:
// TypeObject: AnyType
// Union: zero value of the type at index 0
// These are translated into Go as follows, with their standard Go zero values:
// *Type: nil
// interface: nil
// Thus we must special-case values of these types.
//
// TODO(toddw): This logic is recursive and complicated because our convTarget
// methods don't take the convTarget as a pointer receiver, so we can't mutate
// the target as we decode. When we split convTarget into separate valueTarget
// and reflectTarget objects, we should also take the target as a pointer
// receiver. That'll simplify this logic.
func rvSettableZeroValue(rt reflect.Type, tt *Type) reflect.Value {
rv := reflect.New(rt).Elem()
// Easy fastpath; if the type doesn't contain inline typeobject or union, the
// regular Go zero value is good enough.
if !tt.ContainsKind(WalkInline, TypeObject, Union) {
return rv
}
// Handle typeobject, which has the zero value of AnyType.
if rtPtrToType.ConvertibleTo(rt) {
return reflect.ValueOf(AnyType).Convert(rt)
}
// Handle composite types with inline subtypes.
switch {
case tt.Kind() == Union:
if nativeInfoFromNative(rt) != nil {
return rv
}
if rt.Kind() == reflect.Struct {
// Union struct, which represents a single field.
rv.Field(0).Set(rvSettableZeroValue(rt.Field(0).Type, tt.Field(0).Type))
return rv
}
// Union interface, which represents one of the fields. Initialize with the
// zero value of the type at index 0.
ri, _, err := deriveReflectInfo(rt)
if err != nil {
panic(fmt.Errorf("vdl: invalid union type rt: %v tt: %v err: %v", rt, tt, err))
}
rv.Set(rvSettableZeroValue(ri.UnionFields[0].RepType, tt.Field(0).Type))
return rv
case rt.Kind() == reflect.Array:
for ix := 0; ix < rt.Len(); ix++ {
rv.Index(ix).Set(rvSettableZeroValue(rt.Elem(), tt.Elem()))
}
return rv
case rt.Kind() == reflect.Struct:
for ix := 0; ix < rt.NumField(); ix++ {
rtField := rt.Field(ix)
ttField, index := tt.FieldByName(rtField.Name)
if index < 0 {
// Ignore fields that aren't described in tt; e.g. unexported fields.
continue
}
rv.Field(ix).Set(rvSettableZeroValue(rtField.Type, ttField.Type))
}
return rv
}
panic(fmt.Errorf("vdl: rvSettableZeroValue unhandled rt: %v tt: %v", rt, tt))
}
// makeReflectUnion returns the union concrete struct based on the union
// interface type rt, corresponding to the field that is set in vv. The point
// of this machinery is to ensure union can always be created, without any type
// registration.
func makeReflectUnion(rt reflect.Type, vv *Value) (reflect.Value, error) {
// TODO(toddw): Cache the field types for faster access.
ri, _, err := deriveReflectInfo(rt)
if err != nil || len(ri.UnionFields) == 0 {
// If rt isn't a union interface type, it still might be registered, so we
// can get the reflect type from vv.
if rt2 := TypeToReflect(vv.Type()); rt2 != nil {
rt = rt2
ri, _, err = deriveReflectInfo(rt)
}
}
switch {
case err != nil:
return reflect.Value{}, err
case len(ri.UnionFields) == 0 || vv.Kind() != Union:
return reflect.Value{}, fmt.Errorf("vdl: makeReflectUnion(%v, %v) must only be called on Union", rt, vv.Type())
}
index, vvField := vv.UnionField()
if index >= len(ri.UnionFields) {
return reflect.Value{}, fmt.Errorf("vdl: makeReflectUnion(%v, %v) field index %d out of range, len=%d", rt, vv.Type(), index, len(ri.UnionFields))
}
// Run our regular conversion from vvField to rvField. Keep in mind that
// rvField is the concrete union struct, so we convert into Field(0), which
// corresponds to the "Value" field.
rvField := reflect.New(ri.UnionFields[index].RepType).Elem()
target, err := ReflectTarget(rvField.Field(0))
if err != nil {
return reflect.Value{}, err
}
if err := FromValue(target, vvField); err != nil {
return reflect.Value{}, err
}
return rvField, nil
}
func removeOptional(tt *Type) *Type {
if tt.Kind() == Optional {
tt = tt.Elem()
}
return tt
}
// FromNil implements the Target interface method.
func (c convTarget) FromNil(tt *Type) error {
if !compatible(c.tt, tt) {
return fmt.Errorf("types %q and %q aren't compatible", c.tt, tt)
}
if !tt.CanBeNil() || !c.tt.CanBeNil() {
return fmt.Errorf("invalid conversion from %v(nil) to %v", tt, c.tt)
}
if c.vv == nil {
// The strategy is to create new pointers down to either a single pointer,
// or the final interface, and set that to nil. We create all the pointers
// to be consistent with our behavior in the non-nil case, where we
// similarly create all the pointers. It also makes the tests simpler.
rv := c.rv
for rv.Kind() == reflect.Ptr {
if vv := setZeroVDLValue(rv, tt); vv.IsValid() {
return nil
}
if k := rv.Type().Elem().Kind(); k != reflect.Ptr && k != reflect.Interface {
break
}
// Next elem is a pointer or interface, keep looping.
if rv.IsNil() {
rv.Set(reflect.New(rv.Type().Elem()))
}
rv = rv.Elem()
}
// Now rv.Type is either a single pointer or an interface. If it is an
// interface, check to see whether we can create a Go object from tt.
rt := rv.Type()
if rv.Kind() == reflect.Interface {
if rtFromTT := TypeToReflect(tt); rtFromTT != nil {
rt = rtFromTT
}
}
// Set the zero value of the pointer or interface, which will give us nil of
// the correct type.
rv.Set(reflect.Zero(rt))
} else {
vvNil := ZeroValue(tt)
if to, from := c.vv.Type(), vvNil; !to.AssignableFrom(from) {
return fmt.Errorf("%v not assignable from %v", to, from)
}
c.vv.Assign(vvNil)
}
return nil
}
// FromBool implements the Target interface method.
func (c convTarget) FromBool(src bool, tt *Type) error {
fin, fill, err := startConvert(c, tt)
if err != nil {
return err
}
if err := fill.fromBool(src); err != nil {
return err
}
return finishConvert(fin, fill)
}
// FromUint implements the Target interface method.
func (c convTarget) FromUint(src uint64, tt *Type) error {
fin, fill, err := startConvert(c, tt)
if err != nil {
return err
}
if err := fill.fromUint(src); err != nil {
return err
}
return finishConvert(fin, fill)
}
// FromInt implements the Target interface method.
func (c convTarget) FromInt(src int64, tt *Type) error {
fin, fill, err := startConvert(c, tt)
if err != nil {
return err
}
if err := fill.fromInt(src); err != nil {
return err
}
return finishConvert(fin, fill)
}
// FromFloat implements the Target interface method.
func (c convTarget) FromFloat(src float64, tt *Type) error {
fin, fill, err := startConvert(c, tt)
if err != nil {
return err
}
if err := fill.fromFloat(src); err != nil {
return err
}
return finishConvert(fin, fill)
}
// FromComplex implements the Target interface method.
func (c convTarget) FromComplex(src complex128, tt *Type) error {
fin, fill, err := startConvert(c, tt)
if err != nil {
return err
}
if err := fill.fromComplex(src); err != nil {
return err
}
return finishConvert(fin, fill)
}
// FromBytes implements the Target interface method.
func (c convTarget) FromBytes(src []byte, tt *Type) error {
fin, fill, err := startConvert(c, tt)
if err != nil {
return err
}
if err := fill.fromBytes(src, tt); err != nil {
return err
}
return finishConvert(fin, fill)
}
// FromString implements the Target interface method.
func (c convTarget) FromString(src string, tt *Type) error {
fin, fill, err := startConvert(c, tt)
if err != nil {
return err
}
if err := fill.fromString(src); err != nil {
return err
}
return finishConvert(fin, fill)
}
// FromEnumLabel implements the Target interface method.
func (c convTarget) FromEnumLabel(src string, tt *Type) error {
return c.FromString(src, tt)
}
// FromTypeObject implements the Target interface method.
func (c convTarget) FromTypeObject(src *Type) error {
fin, fill, err := startConvert(c, TypeObjectType)
if err != nil {
return err
}
if err := fill.fromTypeObject(src); err != nil {
return err
}
return finishConvert(fin, fill)
}
func (c convTarget) fromBool(src bool) error {
if c.vv == nil {
if c.rv.Kind() == reflect.Bool {
c.rv.SetBool(src)
return nil
}
} else {
if c.vv.Kind() == Bool {
c.vv.AssignBool(src)
return nil
}
}
return fmt.Errorf("invalid conversion from bool to %v", c.tt)
}
func (c convTarget) fromUint(src uint64) error {
if c.vv == nil {
switch kind := c.rv.Kind(); kind {
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr:
if !overflowUint(src, bitlenR(kind)) {
c.rv.SetUint(src)
return nil
}
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
if isrc, ok := convertUintToInt(src, bitlenR(kind)); ok {
c.rv.SetInt(isrc)
return nil
}
case reflect.Float32, reflect.Float64:
if fsrc, ok := convertUintToFloat(src, bitlenR(kind)); ok {
c.rv.SetFloat(fsrc)
return nil
}
case reflect.Complex64, reflect.Complex128:
if fsrc, ok := convertUintToFloat(src, bitlenR(kind)); ok {
c.rv.SetComplex(complex(fsrc, 0))
return nil
}
}
} else {
switch kind := c.vv.Kind(); kind {
case Byte, Uint16, Uint32, Uint64:
if !overflowUint(src, bitlenV(kind)) {
c.vv.AssignUint(src)
return nil
}
case Int8, Int16, Int32, Int64:
if isrc, ok := convertUintToInt(src, bitlenV(kind)); ok {
c.vv.AssignInt(isrc)
return nil
}
case Float32, Float64:
if fsrc, ok := convertUintToFloat(src, bitlenV(kind)); ok {
c.vv.AssignFloat(fsrc)
return nil
}
case Complex64, Complex128:
if fsrc, ok := convertUintToFloat(src, bitlenV(kind)); ok {
c.vv.AssignComplex(complex(fsrc, 0))
return nil
}
}
}
return fmt.Errorf("invalid conversion from uint(%d) to %v", src, c.tt)
}
func (c convTarget) fromInt(src int64) error {
if c.vv == nil {
switch kind := c.rv.Kind(); kind {
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr:
if usrc, ok := convertIntToUint(src, bitlenR(kind)); ok {
c.rv.SetUint(usrc)
return nil
}
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
if !overflowInt(src, bitlenR(kind)) {
c.rv.SetInt(src)
return nil
}
case reflect.Float32, reflect.Float64:
if fsrc, ok := convertIntToFloat(src, bitlenR(kind)); ok {
c.rv.SetFloat(fsrc)
return nil
}
case reflect.Complex64, reflect.Complex128:
if fsrc, ok := convertIntToFloat(src, bitlenR(kind)); ok {
c.rv.SetComplex(complex(fsrc, 0))
return nil
}
}
} else {
switch kind := c.vv.Kind(); kind {
case Byte, Uint16, Uint32, Uint64:
if usrc, ok := convertIntToUint(src, bitlenV(kind)); ok {
c.vv.AssignUint(usrc)
return nil
}
case Int8, Int16, Int32, Int64:
if !overflowInt(src, bitlenV(kind)) {
c.vv.AssignInt(src)
return nil
}
case Float32, Float64:
if fsrc, ok := convertIntToFloat(src, bitlenV(kind)); ok {
c.vv.AssignFloat(fsrc)
return nil
}
case Complex64, Complex128:
if fsrc, ok := convertIntToFloat(src, bitlenV(kind)); ok {
c.vv.AssignComplex(complex(fsrc, 0))
return nil
}
}
}
return fmt.Errorf("invalid conversion from int(%d) to %v", src, c.tt)
}
func (c convTarget) fromFloat(src float64) error {
if c.vv == nil {
switch kind := c.rv.Kind(); kind {
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr:
if usrc, ok := convertFloatToUint(src, bitlenR(kind)); ok {
c.rv.SetUint(usrc)
return nil
}
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
if isrc, ok := convertFloatToInt(src, bitlenR(kind)); ok {
c.rv.SetInt(isrc)
return nil
}
case reflect.Float32, reflect.Float64:
c.rv.SetFloat(convertFloatToFloat(src, bitlenR(kind)))
return nil
case reflect.Complex64, reflect.Complex128:
c.rv.SetComplex(complex(convertFloatToFloat(src, bitlenR(kind)), 0))
return nil
}
} else {
switch kind := c.vv.Kind(); kind {
case Byte, Uint16, Uint32, Uint64:
if usrc, ok := convertFloatToUint(src, bitlenV(kind)); ok {
c.vv.AssignUint(usrc)
return nil
}
case Int8, Int16, Int32, Int64:
if isrc, ok := convertFloatToInt(src, bitlenV(kind)); ok {
c.vv.AssignInt(isrc)
return nil
}
case Float32, Float64:
c.vv.AssignFloat(convertFloatToFloat(src, bitlenV(kind)))
return nil
case Complex64, Complex128:
c.vv.AssignComplex(complex(convertFloatToFloat(src, bitlenV(kind)), 0))
return nil
}
}
return fmt.Errorf("invalid conversion from float(%g) to %v", src, c.tt)
}
func (c convTarget) fromComplex(src complex128) error {
if c.vv == nil {
switch kind := c.rv.Kind(); kind {
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr:
if usrc, ok := convertComplexToUint(src, bitlenR(kind)); ok {
c.rv.SetUint(usrc)
return nil
}
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
if isrc, ok := convertComplexToInt(src, bitlenR(kind)); ok {
c.rv.SetInt(isrc)
return nil
}
case reflect.Float32, reflect.Float64:
if imag(src) == 0 {
c.rv.SetFloat(convertFloatToFloat(real(src), bitlenR(kind)))
return nil
}
case reflect.Complex64, reflect.Complex128:
re := convertFloatToFloat(real(src), bitlenR(kind))
im := convertFloatToFloat(imag(src), bitlenR(kind))
c.rv.SetComplex(complex(re, im))
return nil
}
} else {
switch kind := c.vv.Kind(); kind {
case Byte, Uint16, Uint32, Uint64:
if usrc, ok := convertComplexToUint(src, bitlenV(kind)); ok {
c.vv.AssignUint(usrc)
return nil
}
case Int8, Int16, Int32, Int64:
if isrc, ok := convertComplexToInt(src, bitlenV(kind)); ok {
c.vv.AssignInt(isrc)
return nil
}
case Float32, Float64:
if imag(src) == 0 {
c.vv.AssignFloat(convertFloatToFloat(real(src), bitlenV(kind)))
return nil
}
case Complex64, Complex128:
re := convertFloatToFloat(real(src), bitlenV(kind))
im := convertFloatToFloat(imag(src), bitlenV(kind))
c.vv.AssignComplex(complex(re, im))
return nil
}
}
return fmt.Errorf("invalid conversion from complex(%g) to %v", src, c.tt)
}
func (c convTarget) fromBytes(src []byte, tt *Type) error {
if c.tt.IsBytes() {
return c.fromBytesToBytes(src)
}
elemType := tt.Elem()
for i, b := range src {
elem, err := c.startElem(i)
if err != nil {
return err
}
if err := elem.FromUint(uint64(b), elemType); err != nil {
return err
}
if err := c.finishElem(elem); err != nil {
return err
}
}
return nil
}
func (c convTarget) fromBytesToBytes(src []byte) error {
if c.vv == nil {
switch {
case c.rv.Kind() == reflect.Array:
if c.rv.Type().Elem() == rtByte && c.rv.Len() == len(src) {
reflect.Copy(c.rv, reflect.ValueOf(src))
return nil
}
case c.rv.Kind() == reflect.Slice:
if c.rv.Type().Elem() == rtByte {
if len(src) == 0 {
c.rv.SetBytes(nil)
} else {
cp := make([]byte, len(src))
copy(cp, src)
c.rv.SetBytes(cp)
}
return nil
}
}
} else {
switch c.vv.Kind() {
case Array:
if c.vv.Type().Len() == len(src) {
c.vv.AssignBytes(src)
return nil
}
case List:
c.vv.AssignBytes(src)
return nil
}
}
return fmt.Errorf("invalid conversion from bytes to %v", c.tt)
}
// settable exists to avoid a call to reflect.Call() to invoke Set()
// which results in an allocation
type settable interface {
Set(string) error
}
func (c convTarget) fromString(src string) error {
if c.vv == nil {
tt := removeOptional(c.tt)
switch {
case tt.Kind() == Enum:
// Handle special-case enum first, by calling the Assign method. Note
// that TypeFromReflect has already validated the Assign method, so we
// can call without error checking.
if c.rv.CanAddr() {
err := c.rv.Addr().Interface().(settable).Set(src)
if err != nil {
return err
}
return nil
}
case c.rv.Kind() == reflect.String:
c.rv.SetString(src) // TODO(toddw): check utf8
return nil
}
} else {
switch c.vv.Kind() {
case String:
c.vv.AssignString(src) // TODO(toddw): check utf8
return nil
case Enum:
if index := c.vv.Type().EnumIndex(src); index >= 0 {
c.vv.AssignEnumIndex(index)
return nil
}
}
}
return fmt.Errorf("invalid conversion from string or enum to %v", c.tt)
}
func (c convTarget) fromTypeObject(src *Type) error {
if c.vv == nil {
if rtPtrToType.ConvertibleTo(c.rv.Type()) {
c.rv.Set(reflect.ValueOf(src).Convert(c.rv.Type()))
return nil
}
} else {
if c.vv.Kind() == TypeObject {
c.vv.AssignTypeObject(src)
return nil
}
}
return fmt.Errorf("invalid conversion from typeobject to %v", c.tt)
}
// StartList implements the Target interface method.
func (c convTarget) StartList(tt *Type, len int) (ListTarget, error) {
// TODO(bprosnitz) Re-think allocation strategy and possibly use len (currently unused).
fin, fill, err := startConvert(c, tt)
return compConvTarget{fin, fill}, err
}
// FinishList implements the Target interface method.
func (c convTarget) FinishList(x ListTarget) error {
cc := x.(compConvTarget)
return finishConvert(cc.fin, cc.fill)
}
// StartSet implements the Target interface method.
func (c convTarget) StartSet(tt *Type, len int) (SetTarget, error) {
fin, fill, err := startConvert(c, tt)
return compConvTarget{fin, fill}, err
}
// FinishSet implements the Target interface method.
func (c convTarget) FinishSet(x SetTarget) error {
cc := x.(compConvTarget)
return finishConvert(cc.fin, cc.fill)
}
// StartMap implements the Target interface method.
func (c convTarget) StartMap(tt *Type, len int) (MapTarget, error) {
fin, fill, err := startConvert(c, tt)
return compConvTarget{fin, fill}, err
}
// FinishMap implements the Target interface method.
func (c convTarget) FinishMap(x MapTarget) error {
cc := x.(compConvTarget)
return finishConvert(cc.fin, cc.fill)
}
// StartFields implements the Target interface method.
func (c convTarget) StartFields(tt *Type) (FieldsTarget, error) {
fin, fill, err := startConvert(c, tt)
return compConvTarget{fin, fill}, err
}
// FinishFields implements the Target interface method.
func (c convTarget) FinishFields(x FieldsTarget) error {
cc := x.(compConvTarget)
return finishConvert(cc.fin, cc.fill)
}
// compConvTarget represents the state and logic for composite value conversion.
type compConvTarget struct {
fin, fill convTarget // fields returned by startConvert.
}
// StartElem implements the ListTarget interface method.
func (cc compConvTarget) StartElem(index int) (elem Target, _ error) {
return cc.fill.startElem(index)
}
// FinishElem implements the ListTarget interface method.
func (cc compConvTarget) FinishElem(elem Target) error {
return cc.fill.finishElem(elem.(convTarget))
}
// StartKey implements the SetTarget and MapTarget interface method.
func (cc compConvTarget) StartKey() (key Target, _ error) {
return cc.fill.startKey()
}
// FinishKeyStartField implements the MapTarget interface method.
func (cc compConvTarget) FinishKeyStartField(key Target) (field Target, _ error) {
return cc.fill.finishKeyStartField(key.(convTarget))
}
// FinishField implements the MapTarget and FieldsTarget interface method.
func (cc compConvTarget) FinishField(key, field Target) error {
return cc.fill.finishField(key.(convTarget), field.(convTarget))
}
// StartField implements the FieldsTarget interface method.
func (cc compConvTarget) StartField(name string) (key, field Target, _ error) {
var err error
if key, err = cc.StartKey(); err != nil {
return nil, nil, err
}
if err = key.FromString(name, StringType); err != nil {
return nil, nil, err
}
if field, err = cc.FinishKeyStartField(key); err != nil {
return nil, nil, err
}
return
}
// FinishKey implements the SetTarget interface method.
func (cc compConvTarget) FinishKey(key Target) error {
field, err := cc.FinishKeyStartField(key)
if err != nil {
return err
}
return cc.FinishField(key, field)
}
func (c convTarget) startElem(index int) (convTarget, error) {
if c.vv == nil {
tt := removeOptional(c.tt)
switch c.rv.Kind() {
case reflect.Array:
if index >= c.rv.Len() {
return convTarget{}, errArrayIndex
}
return reflectConv(c.rv.Index(index), tt.Elem())
case reflect.Slice:
newlen := index + 1
if newlen < c.rv.Len() {
newlen = c.rv.Len()
}
if newlen > c.rv.Cap() {
rvNew := reflect.MakeSlice(c.rv.Type(), newlen, newlen*2)
reflect.Copy(rvNew, c.rv)
c.rv.Set(rvNew)
} else {
c.rv.SetLen(newlen)
}
return reflectConv(c.rv.Index(index), tt.Elem())
}
} else {
switch c.vv.Kind() {
case Array:
if index >= c.vv.Len() {
return convTarget{}, errArrayIndex
}
return valueConv(c.vv.Index(index)), nil
case List:
newlen := index + 1
if newlen < c.vv.Len() {
newlen = c.vv.Len()
}
return valueConv(c.vv.AssignLen(newlen).Index(index)), nil
}
}
return convTarget{}, fmt.Errorf("type %v doesn't support StartElem", c.tt)
}
func (c convTarget) finishElem(elem convTarget) error {
if c.vv == nil {
switch c.rv.Kind() {
case reflect.Array, reflect.Slice:
return nil
}
} else {
switch c.vv.Kind() {
case Array, List:
return nil
}
}
return fmt.Errorf("type %v doesn't support FinishElem", c.tt)
}
func (c convTarget) startKey() (convTarget, error) {
if c.vv == nil {
tt := removeOptional(c.tt)
switch c.rv.Kind() {
case reflect.Map:
return reflectConv(rvSettableZeroValue(c.rv.Type().Key(), tt.Key()), tt.Key())
case reflect.Struct:
// The key for struct is the field name, which is a string.
return reflectConv(reflect.New(rtString).Elem(), StringType)
}
} else {
switch c.vv.Kind() {
case Set, Map:
return valueConv(ZeroValue(c.vv.Type().Key())), nil
case Struct, Union:
// The key for struct and union is the field name, which is a string.
return valueConv(ZeroValue(StringType)), nil
}
}
return convTarget{}, fmt.Errorf("type %v doesn't support StartKey", c.tt)
}
func (c convTarget) finishKeyStartField(key convTarget) (convTarget, error) {
// There are various special-cases regarding bool values below. These are to
// handle different representations of sets; the following types are all
// convertible to each other:
// set[string], map[string]bool, struct{X, Y, Z bool}
//
// To deal with these cases in a uniform manner, we return a bool field for
// set[string], and initialize bool fields to true.
if c.vv == nil {
tt := removeOptional(c.tt)
switch c.rv.Kind() {
case reflect.Map:
var ttField *Type
var rvField reflect.Value
switch rtField := c.rv.Type().Elem(); {
case tt.Kind() == Set:
// The map actually represents a set
ttField = BoolType
rvField = reflect.New(rtBool).Elem()
rvField.SetBool(true)
case rtField.Kind() == reflect.Bool:
ttField = tt.Elem()
rvField = reflect.New(rtField).Elem()
rvField.SetBool(true)
default:
// TODO(toddw): This doesn't work correctly for map[_]any.
ttField = tt.Elem()
rvField = rvSettableZeroValue(rtField, ttField)
}
return reflectConv(rvField, ttField)
case reflect.Struct:
if tt.Kind() == Union {
// Special-case: the fill target is a union concrete field struct. This
// means that we should only return a field if the field name matches.
name := c.rv.Interface().(nameable).Name()
if name != key.rv.String() {
return convTarget{}, ErrFieldNoExist
}
ttField, _ := tt.FieldByName(name)
return reflectConv(c.rv.FieldByName("Value"), ttField.Type)
}
rvField := c.rv.FieldByName(key.rv.String())
ttField, index := tt.FieldByName(key.rv.String())
if !rvField.IsValid() || index < 0 {
// TODO(toddw): Add a way to track extra and missing fields.
return convTarget{}, ErrFieldNoExist
}
if rvField.Kind() == reflect.Bool {
rvField.SetBool(true)
}
return reflectConv(rvField, ttField.Type)
}
} else {
switch c.vv.Kind() {
case Set:
return valueConv(BoolValue(true)), nil
case Map:
vvField := ZeroValue(c.vv.Type().Elem())
if vvField.Kind() == Bool {
vvField.AssignBool(true)
}
return valueConv(vvField), nil
case Struct:
_, index := c.vv.Type().FieldByName(key.vv.RawString())
if index < 0 {
// TODO(toddw): Add a way to track extra and missing fields.
return convTarget{}, ErrFieldNoExist
}
vvField := c.vv.StructField(index)
if vvField.Kind() == Bool {
vvField.AssignBool(true)
}
return valueConv(vvField), nil
case Union:
f, index := c.vv.Type().FieldByName(key.vv.RawString())
if index < 0 {
return convTarget{}, ErrFieldNoExist
}
vvField := ZeroValue(f.Type)
return valueConv(vvField), nil
}
}
return convTarget{}, fmt.Errorf("type %v doesn't support FinishKeyStartField", c.tt)
}
func (c convTarget) finishField(key, field convTarget) error {
// The special-case handling of bool fields matches the special-cases in
// FinishKeyStartField.
if c.vv == nil {
tt := removeOptional(c.tt)
switch c.rv.Kind() {
case reflect.Map:
rvField := field.rv
if tt.Kind() == Set {
// The map actually represents a set
if !field.rv.Bool() {
return fmt.Errorf("%v can only be converted from true fields", tt)
}
rvField = reflect.Zero(c.rv.Type().Elem())
}
if c.rv.IsNil() {
c.rv.Set(reflect.MakeMap(c.rv.Type()))
}
c.rv.SetMapIndex(key.rv, rvField)
return nil
case reflect.Struct:
return nil
}
} else {
switch c.vv.Kind() {
case Set:
if !field.vv.Bool() {
return fmt.Errorf("%v can only be converted from true fields", c.vv.Type())
}
c.vv.AssignSetKey(key.vv)
return nil
case Map:
c.vv.AssignMapIndex(key.vv, field.vv)
return nil
case Struct:
return nil
case Union:
_, index := c.vv.Type().FieldByName(key.vv.RawString())
c.vv.AssignUnionField(index, field.vv)
return nil
}
}
return fmt.Errorf("type %v doesn't support FinishField", c.tt)
}