forked from r3labs/diff
-
Notifications
You must be signed in to change notification settings - Fork 0
/
patch_slice.go
78 lines (73 loc) · 2.42 KB
/
patch_slice.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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)
}
}