func reifyMergeValue()

in reify.go [434:511]


func reifyMergeValue(
	opts fieldOptions,
	oldValue reflect.Value, val value,
) (reflect.Value, Error) {
	old := chaseValueInterfaces(oldValue)
	t := old.Type()
	old = chaseValuePointers(old)
	if (old.Kind() == reflect.Ptr || old.Kind() == reflect.Interface) && old.IsNil() {
		return reifyValue(opts, t, val)
	}

	baseType := chaseTypePointers(old.Type())

	if tConfig.ConvertibleTo(baseType) {
		sub, err := val.toConfig(opts.opts)
		if err != nil {
			return reflect.Value{}, raiseExpectedObject(opts.opts, val)
		}

		if t == baseType {
			// no pointer -> return type mismatch
			return reflect.Value{}, raisePointerRequired(oldValue)
		}

		// check if old is nil -> copy reference only
		if old.Kind() == reflect.Ptr && old.IsNil() {
			v, err := val.reflect(opts.opts)
			if err != nil {
				ctx := val.Context()
				return reflect.Value{}, raisePathErr(err, val.meta(), "", ctx.path("."))
			}

			v = v.Convert(reflect.PtrTo(baseType))
			return pointerize(t, baseType, v), nil
		}

		// check if old == value
		subOld := chaseValuePointers(old).Addr().Convert(tConfigPtr).Interface().(*Config)
		if sub == subOld {
			return oldValue, nil
		}

		// old != value -> merge value into old
		return oldValue, mergeFieldConfig(opts, subOld, sub)
	}

	if v, ok := valueIsUnpacker(old); ok {
		err := unpackWith(opts.opts, v, val)
		if err != nil {
			return reflect.Value{}, err
		}
		return old, nil
	}

	switch baseType.Kind() {
	case reflect.Map:
		sub, err := val.toConfig(opts.opts)
		if err != nil {
			return reflect.Value{}, raiseExpectedObject(opts.opts, val)
		}
		return old, reifyMap(opts.opts, old, sub, opts.validators)

	case reflect.Struct:
		sub, err := val.toConfig(opts.opts)
		if err != nil {
			return reflect.Value{}, raiseExpectedObject(opts.opts, val)
		}
		return oldValue, reifyStruct(opts.opts, old, sub)

	case reflect.Array:
		return reifyArray(opts, old, baseType, val)

	case reflect.Slice:
		return reifySliceMerge(opts, old, baseType, val)
	}

	return reifyPrimitive(opts, val, t, baseType)
}