func reifyStruct()

in reify.go [244:305]


func reifyStruct(opts *options, orig reflect.Value, cfg *Config) Error {
	parentFields := opts.activeFields
	defer func() { opts.activeFields = parentFields }()

	orig = chaseValuePointers(orig)

	to := chaseValuePointers(reflect.New(chaseTypePointers(orig.Type())))
	if orig.Kind() == reflect.Struct { // if orig is has been allocated copy into to
		to.Set(orig)
	}

	if v, ok := valueIsUnpacker(to); ok {
		err := unpackWith(opts, v, cfgSub{cfg})
		if err != nil {
			return err
		}
	} else {
		tryInitDefaults(to)
		numField := to.NumField()
		for i := 0; i < numField; i++ {
			fInfo, skip, err := accessField(to, i, opts)
			if err != nil {
				return err
			}
			if skip {
				continue
			}

			if fInfo.tagOptions.squash {
				vField := chaseValue(fInfo.value)
				switch vField.Kind() {
				case reflect.Struct, reflect.Map:
					if err := reifyInto(fInfo.options, fInfo.value, cfg); err != nil {
						return err
					}
				case reflect.Slice, reflect.Array:
					fopts := fieldOptions{opts: fInfo.options, tag: fInfo.tagOptions, validators: fInfo.validatorTags}
					v, err := reifyMergeValue(fopts, fInfo.value, cfgSub{cfg})
					if err != nil {
						return err
					}
					vField.Set(v)

				default:
					return raiseInlineNeedsObject(cfg, fInfo.name, fInfo.value.Type())
				}
			} else {
				fopts := fieldOptions{opts: fInfo.options, tag: fInfo.tagOptions, validators: fInfo.validatorTags}
				if err := reifyGetField(cfg, fopts, fInfo.name, fInfo.value, fInfo.ftype); err != nil {
					return err
				}
			}
		}
	}

	if err := tryValidate(to); err != nil {
		return raiseValidation(cfg.ctx, cfg.metadata, "", err)
	}

	orig.Set(pointerize(orig.Type(), to.Type(), to))
	return nil
}