func()

in internal/kernel/conversions.go [137:225]


func (c *Client) CastPtrToRef(dataVal reflect.Value) interface{} {
	if !dataVal.IsValid() {
		// dataVal is a 0-value, meaning we have no value available... We return
		// this to JavaScript as a "null" value.
		return nil
	}
	if (dataVal.Kind() == reflect.Interface || dataVal.Kind() == reflect.Ptr) && dataVal.IsNil() {
		return nil
	}

	// In case we got a time.Time value (or pointer to one).
	if wireDate, isDate := castPtrToDate(dataVal); isDate {
		return wireDate
	}

	switch dataVal.Kind() {
	case reflect.Map:
		result := api.WireMap{MapData: make(map[string]interface{})}

		iter := dataVal.MapRange()
		for iter.Next() {
			key := iter.Key().String()
			val := iter.Value()
			result.MapData[key] = c.CastPtrToRef(val)
		}

		return result

	case reflect.Interface, reflect.Ptr:
		if valref, valHasRef := c.FindObjectRef(dataVal); valHasRef {
			return valref
		}

		// In case we got a pointer to a map, slice, enum, ...
		if elem := reflect.Indirect(dataVal.Elem()); elem.Kind() != reflect.Struct {
			return c.CastPtrToRef(elem)
		}

		if dataVal.Elem().Kind() == reflect.Struct {
			elemVal := dataVal.Elem()
			if fields, fqn, isStruct := c.Types().StructFields(elemVal.Type()); isStruct {
				data := make(map[string]interface{})
				for _, field := range fields {
					fieldVal := elemVal.FieldByIndex(field.Index)
					if (fieldVal.Kind() == reflect.Ptr || fieldVal.Kind() == reflect.Interface) && fieldVal.IsNil() {
						// If there is the "field" tag, and it's "required", then panic since the value is nil.
						if requiredOrOptional, found := field.Tag.Lookup("field"); found && requiredOrOptional == "required" {
							panic(fmt.Sprintf("Field %v.%v is required, but has nil value", field.Type, field.Name))
						}
						continue
					}
					key := field.Tag.Get("json")
					data[key] = c.CastPtrToRef(fieldVal)
				}

				return api.WireStruct{
					StructDescriptor: api.StructDescriptor{
						FQN:    fqn,
						Fields: data,
					},
				}
			}
		} else if dataVal.Elem().Kind() == reflect.Ptr {
			// Typically happens when a struct pointer is passed into an interface{}
			// typed API (such as a place where a union is accepted).
			elemVal := dataVal.Elem()
			return c.CastPtrToRef(elemVal)
		}

		if ref, err := c.ManageObject(dataVal); err != nil {
			panic(err)
		} else {
			return ref
		}

	case reflect.Slice:
		refs := make([]interface{}, dataVal.Len())
		for i := 0; i < dataVal.Len(); i++ {
			refs[i] = c.CastPtrToRef(dataVal.Index(i))
		}
		return refs

	case reflect.String:
		if enumRef, isEnumRef := c.Types().TryRenderEnumRef(dataVal); isEnumRef {
			return enumRef
		}
	}
	return dataVal.Interface()
}