in packages/@jsii/go-runtime/jsii-runtime-go/internal/kernel/conversions.go [28:131]
func (c *Client) castAndSetToPtr(ptr reflect.Value, data reflect.Value) {
if !data.IsValid() {
// data will not be valid if was made from a nil value, as there would
// not have been enough type information available to build a valid
// reflect.Value. In such cases, we must craft the correctly-typed zero
// value ourselves.
data = reflect.Zero(ptr.Type())
} else if ptr.Kind() == reflect.Ptr && ptr.IsNil() {
// if ptr is a Pointer type and data is valid, initialize a non-nil pointer
// type. Otherwise inner value is not-settable upon recursion. See third
// law of reflection.
// https://blog.golang.org/laws-of-reflection
ptr.Set(reflect.New(ptr.Type().Elem()))
c.castAndSetToPtr(ptr.Elem(), data)
return
} else if data.Kind() == reflect.Interface && !data.IsNil() {
// If data is a non-nil interface, unwrap it to get it's dynamic value
// type sorted out, so that further calls in this method don't have to
// worry about this edge-case when reasoning on kinds.
data = reflect.ValueOf(data.Interface())
}
if ref, isRef := castValToRef(data); isRef {
// If return data is a jsii struct passed by reference, de-reference it all.
if fields, _, isStruct := c.Types().StructFields(ptr.Type()); isStruct {
for _, field := range fields {
got, err := c.Get(GetProps{
Property: field.Tag.Get("json"),
ObjRef: ref,
})
if err != nil {
panic(err)
}
fieldVal := ptr.FieldByIndex(field.Index)
c.castAndSetToPtr(fieldVal, reflect.ValueOf(got.Value))
}
return
}
targetType := ptr.Type()
if typ, ok := c.Types().FindType(ref.TypeFQN()); ok && typ.AssignableTo(ptr.Type()) {
// Specialize the return type to be the dynamic value type
targetType = typ
}
// If it's currently tracked, return the current instance
if object, ok := c.objects.GetObjectAs(ref.InstanceID, targetType); ok {
ptr.Set(object)
return
}
// If return data is jsii object references, add to objects table.
if err := c.Types().InitJsiiProxy(ptr, targetType); err == nil {
if err = c.RegisterInstance(ptr, ref); err != nil {
panic(err)
}
} else {
panic(err)
}
return
}
if enumref, isEnum := castValToEnumRef(data); isEnum {
member, err := c.Types().EnumMemberForEnumRef(enumref)
if err != nil {
panic(err)
}
ptr.Set(reflect.ValueOf(member))
return
}
if date, isDate := castValToDate(data); isDate {
ptr.Set(reflect.ValueOf(date))
return
}
// maps
if m, isMap := c.castValToMap(data, ptr.Type()); isMap {
ptr.Set(m)
return
}
// arrays
if data.Kind() == reflect.Slice {
len := data.Len()
var slice reflect.Value
if ptr.Kind() == reflect.Slice {
slice = reflect.MakeSlice(ptr.Type(), len, len)
} else {
slice = reflect.MakeSlice(reflect.SliceOf(anyType), len, len)
}
// If return type is a slice, recursively cast elements
for i := 0; i < len; i++ {
c.castAndSetToPtr(slice.Index(i), data.Index(i))
}
ptr.Set(slice)
return
}
ptr.Set(data)
}