package diff /** Types are being split out to more closely follow the library structure already in place. Keeps the file simpler as well. */ import ( "reflect" "strconv" ) //renderSlice - handle slice rendering for patch func (d *Differ) renderSlice(c *ChangeValue) { var err error field := c.change.Path[c.pos] //field better be an index of the slice if c.index, err = strconv.Atoi(field); err != nil { //if struct element is has identifier, use it instead if identifier(d.TagName, reflect.Zero(c.target.Type().Elem())) != nil { for c.index = 0; c.index < c.Len(); c.index++ { if identifier(d.TagName, c.Index(c.index)) == field { break } } } else { c.AddError(NewErrorf("invalid index in path. %s is not a number", field). WithCause(err)) } } var x reflect.Value if c.Len() > c.index { x = c.Index(c.index) } else if c.change.Type == CREATE && !c.HasFlag(OptionNoCreate) { x = c.NewArrayElement() } if !x.IsValid() { if !c.HasFlag(OptionOmitUnequal) { c.AddError(NewErrorf("Value index %d is invalid", c.index). WithCause(NewError("scanning for Value index"))) for c.index = 0; c.index < c.Len(); c.index++ { y := c.Index(c.index) if reflect.DeepEqual(y, c.change.From) { c.AddError(NewErrorf("Value changed index to %d", c.index)) x = y break } } } } if !x.IsValid() && c.change.Type != DELETE && !c.HasFlag(OptionNoCreate) { x = c.NewArrayElement() } if !x.IsValid() && c.change.Type == DELETE { c.index = -1 //no existing element to delete so don't bother } c.swap(&x) //containers must swap out the parent Value } //deleteSliceEntry - deletes are special, they are handled differently based on options // container type etc. We have to have special handling for each // type. Set values are more generic even if they must be instanced func (d *Differ) deleteSliceEntry(c *ChangeValue) { //for a slice with only one element if c.ParentLen() == 1 && c.index != -1 { c.ParentSet(reflect.MakeSlice(c.parent.Type(), 0, 0), d.ConvertCompatibleTypes) c.SetFlag(FlagDeleted) //for a slice with multiple elements } else if c.index != -1 { //this is an array delete the element from the parent c.ParentIndex(c.index).Set(c.ParentIndex(c.ParentLen() - 1)) c.ParentSet(c.parent.Slice(0, c.ParentLen()-1), d.ConvertCompatibleTypes) c.SetFlag(FlagDeleted) //for other slice elements, we ignore } else { c.SetFlag(FlagIgnored) } }