/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package diff import ( "reflect" "time" ) func (d *Differ) diffStruct(path []string, a, b reflect.Value, parent interface{}) error { if AreType(a, b, reflect.TypeOf(time.Time{})) { return d.diffTime(path, a, b) } if a.Kind() == reflect.Invalid { if d.DisableStructValues { d.cl.Add(CREATE, path, nil, exportInterface(b)) return nil } return d.structValues(CREATE, path, b) } if b.Kind() == reflect.Invalid { if d.DisableStructValues { d.cl.Add(DELETE, path, exportInterface(a), nil) return nil } return d.structValues(DELETE, path, a) } for i := 0; i < a.NumField(); i++ { field := a.Type().Field(i) tname := tagName(d.TagName, field) if tname == "-" || hasTagOption(d.TagName, field, "immutable") { continue } if tname == "" { tname = field.Name } af := a.Field(i) bf := b.FieldByName(field.Name) fpath := path if !(d.FlattenEmbeddedStructs && field.Anonymous) { fpath = copyAppend(fpath, tname) } if d.Filter != nil && !d.Filter(fpath, a.Type(), field) { continue } // skip private fields if !a.CanInterface() { continue } err := d.diff(fpath, af, bf, exportInterface(a)) if err != nil { return err } } return nil } func (d *Differ) structValues(t string, path []string, a reflect.Value) error { var nd Differ nd.Filter = d.Filter nd.customValueDiffers = d.customValueDiffers if t != CREATE && t != DELETE { return ErrInvalidChangeType } if a.Kind() == reflect.Ptr { a = reflect.Indirect(a) } if a.Kind() != reflect.Struct { return ErrTypeMismatch } x := reflect.New(a.Type()).Elem() for i := 0; i < a.NumField(); i++ { field := a.Type().Field(i) tname := tagName(d.TagName, field) if tname == "-" { continue } if tname == "" { tname = field.Name } af := a.Field(i) xf := x.FieldByName(field.Name) fpath := copyAppend(path, tname) if nd.Filter != nil && !nd.Filter(fpath, a.Type(), field) { continue } err := nd.diff(fpath, xf, af, exportInterface(a)) if err != nil { return err } } for i := 0; i < len(nd.cl); i++ { (d.cl) = append(d.cl, swapChange(t, nd.cl[i])) } return nil }