1
16
17 package typed
18
19 import (
20 "sync"
21
22 "sigs.k8s.io/structured-merge-diff/v4/fieldpath"
23 "sigs.k8s.io/structured-merge-diff/v4/schema"
24 "sigs.k8s.io/structured-merge-diff/v4/value"
25 )
26
27
28 type ValidationOptions int
29
30 const (
31
32 AllowDuplicates ValidationOptions = iota
33 )
34
35
36
37
38 func AsTyped(v value.Value, s *schema.Schema, typeRef schema.TypeRef, opts ...ValidationOptions) (*TypedValue, error) {
39 tv := &TypedValue{
40 value: v,
41 typeRef: typeRef,
42 schema: s,
43 }
44 if err := tv.Validate(opts...); err != nil {
45 return nil, err
46 }
47 return tv, nil
48 }
49
50
51
52
53
54
55
56
57
58 func AsTypedUnvalidated(v value.Value, s *schema.Schema, typeRef schema.TypeRef) *TypedValue {
59 tv := &TypedValue{
60 value: v,
61 typeRef: typeRef,
62 schema: s,
63 }
64 return tv
65 }
66
67
68 type TypedValue struct {
69 value value.Value
70 typeRef schema.TypeRef
71 schema *schema.Schema
72 }
73
74
75 func (tv TypedValue) TypeRef() schema.TypeRef {
76 return tv.typeRef
77 }
78
79
80 func (tv TypedValue) AsValue() value.Value {
81 return tv.value
82 }
83
84
85 func (tv TypedValue) Schema() *schema.Schema {
86 return tv.schema
87 }
88
89
90 func (tv TypedValue) Validate(opts ...ValidationOptions) error {
91 w := tv.walker()
92 for _, opt := range opts {
93 switch opt {
94 case AllowDuplicates:
95 w.allowDuplicates = true
96 }
97 }
98 defer w.finished()
99 if errs := w.validate(nil); len(errs) != 0 {
100 return errs
101 }
102 return nil
103 }
104
105
106
107 func (tv TypedValue) ToFieldSet() (*fieldpath.Set, error) {
108 w := tv.toFieldSetWalker()
109 defer w.finished()
110 if errs := w.toFieldSet(); len(errs) != 0 {
111 return nil, errs
112 }
113 return w.set, nil
114 }
115
116
117
118
119
120
121
122
123
124
125
126
127
128 func (tv TypedValue) Merge(pso *TypedValue) (*TypedValue, error) {
129 return merge(&tv, pso, ruleKeepRHS, nil)
130 }
131
132 var cmpwPool = sync.Pool{
133 New: func() interface{} { return &compareWalker{} },
134 }
135
136
137
138
139
140
141
142 func (tv TypedValue) Compare(rhs *TypedValue) (c *Comparison, err error) {
143 lhs := tv
144 if lhs.schema != rhs.schema {
145 return nil, errorf("expected objects with types from the same schema")
146 }
147 if !lhs.typeRef.Equals(&rhs.typeRef) {
148 return nil, errorf("expected objects of the same type, but got %v and %v", lhs.typeRef, rhs.typeRef)
149 }
150
151 cmpw := cmpwPool.Get().(*compareWalker)
152 defer func() {
153 cmpw.lhs = nil
154 cmpw.rhs = nil
155 cmpw.schema = nil
156 cmpw.typeRef = schema.TypeRef{}
157 cmpw.comparison = nil
158 cmpw.inLeaf = false
159
160 cmpwPool.Put(cmpw)
161 }()
162
163 cmpw.lhs = lhs.value
164 cmpw.rhs = rhs.value
165 cmpw.schema = lhs.schema
166 cmpw.typeRef = lhs.typeRef
167 cmpw.comparison = &Comparison{
168 Removed: fieldpath.NewSet(),
169 Modified: fieldpath.NewSet(),
170 Added: fieldpath.NewSet(),
171 }
172 if cmpw.allocator == nil {
173 cmpw.allocator = value.NewFreelistAllocator()
174 }
175
176 errs := cmpw.compare(nil)
177 if len(errs) > 0 {
178 return nil, errs
179 }
180 return cmpw.comparison, nil
181 }
182
183
184 func (tv TypedValue) RemoveItems(items *fieldpath.Set) *TypedValue {
185 tv.value = removeItemsWithSchema(tv.value, items, tv.schema, tv.typeRef, false)
186 return &tv
187 }
188
189
190 func (tv TypedValue) ExtractItems(items *fieldpath.Set) *TypedValue {
191 tv.value = removeItemsWithSchema(tv.value, items, tv.schema, tv.typeRef, true)
192 return &tv
193 }
194
195 func (tv TypedValue) Empty() *TypedValue {
196 tv.value = value.NewValueInterface(nil)
197 return &tv
198 }
199
200 var mwPool = sync.Pool{
201 New: func() interface{} { return &mergingWalker{} },
202 }
203
204 func merge(lhs, rhs *TypedValue, rule, postRule mergeRule) (*TypedValue, error) {
205 if lhs.schema != rhs.schema {
206 return nil, errorf("expected objects with types from the same schema")
207 }
208 if !lhs.typeRef.Equals(&rhs.typeRef) {
209 return nil, errorf("expected objects of the same type, but got %v and %v", lhs.typeRef, rhs.typeRef)
210 }
211
212 mw := mwPool.Get().(*mergingWalker)
213 defer func() {
214 mw.lhs = nil
215 mw.rhs = nil
216 mw.schema = nil
217 mw.typeRef = schema.TypeRef{}
218 mw.rule = nil
219 mw.postItemHook = nil
220 mw.out = nil
221 mw.inLeaf = false
222
223 mwPool.Put(mw)
224 }()
225
226 mw.lhs = lhs.value
227 mw.rhs = rhs.value
228 mw.schema = lhs.schema
229 mw.typeRef = lhs.typeRef
230 mw.rule = rule
231 mw.postItemHook = postRule
232 if mw.allocator == nil {
233 mw.allocator = value.NewFreelistAllocator()
234 }
235
236 errs := mw.merge(nil)
237 if len(errs) > 0 {
238 return nil, errs
239 }
240
241 out := &TypedValue{
242 schema: lhs.schema,
243 typeRef: lhs.typeRef,
244 }
245 if mw.out != nil {
246 out.value = value.NewValueInterface(*mw.out)
247 }
248 return out, nil
249 }
250
View as plain text