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
}