@@ -25,55 +25,85 @@ import (
25
25
"sigs.k8s.io/structured-merge-diff/value"
26
26
)
27
27
28
- // TypedValue is a value of some specific type.
29
- type TypedValue struct {
30
- value value.Value
31
- typeRef schema.TypeRef
32
- schema * schema.Schema
28
+ // TypedValue is a value with an associated type.
29
+ type TypedValue interface {
30
+ // AsValue removes the type from the TypedValue and only keeps the value.
31
+ AsValue () * value.Value
32
+ // Validate returns an error with a list of every spec violation.
33
+ Validate () error
34
+ // ToFieldSet creates a set containing every leaf field mentioned, or
35
+ // validation errors, if any were encountered.
36
+ ToFieldSet () (* fieldpath.Set , error )
37
+ // Merge returns the result of merging tv and pso ("partially specified
38
+ // object") together. Of note:
39
+ // * No fields can be removed by this operation.
40
+ // * If both tv and pso specify a given leaf field, the result will keep pso's
41
+ // value.
42
+ // * Container typed elements will have their items ordered:
43
+ // * like tv, if pso doesn't change anything in the container
44
+ // * like pso, if pso does change something in the container.
45
+ // tv and pso must both be of the same type (their Schema and TypeRef must
46
+ // match), or an error will be returned. Validation errors will be returned if
47
+ // the objects don't conform to the schema.
48
+ Merge (pso TypedValue ) (TypedValue , error )
49
+ // Compare compares the two objects. See the comments on the `Comparison`
50
+ // struct for details on the return value.
51
+ //
52
+ // tv and rhs must both be of the same type (their Schema and TypeRef must
53
+ // match), or an error will be returned. Validation errors will be returned if
54
+ // the objects don't conform to the schema.
55
+ Compare (rhs TypedValue ) (c * Comparison , err error )
33
56
}
34
57
35
58
// AsTyped accepts a value and a type and returns a TypedValue. 'v' must have
36
59
// type 'typeName' in the schema. An error is returned if the v doesn't conform
37
60
// to the schema.
38
61
func AsTyped (v value.Value , s * schema.Schema , typeName string ) (TypedValue , error ) {
39
- tv := TypedValue {
62
+ tv := typedValue {
40
63
value : v ,
41
64
typeRef : schema.TypeRef {NamedType : & typeName },
42
65
schema : s ,
43
66
}
44
67
if err := tv .Validate (); err != nil {
45
- return TypedValue {} , err
68
+ return nil , err
46
69
}
47
70
return tv , nil
48
71
}
49
72
50
- // AsTypedDeduced is going to generate it's own type definition based on
51
- // the content of the object. This is useful for CRDs that don't have a
52
- // validation field.
53
- func AsTypedDeduced (v value.Value ) TypedValue {
54
- return TypedValue {
55
- value : v ,
56
- typeRef : schema .TypeRefFromValue (v ),
57
- schema : nil ,
73
+ // AsTypeUnvalidated is just like AsTyped, but doesn't validate that the type
74
+ // conforms to the schema, for cases where that has already been checked or
75
+ // where you're going to call a method that validates as a side-effect (like
76
+ // ToFieldSet).
77
+ func AsTypedUnvalidated (v value.Value , s * schema.Schema , typeName string ) TypedValue {
78
+ tv := typedValue {
79
+ value : v ,
80
+ typeRef : schema.TypeRef {NamedType : & typeName },
81
+ schema : s ,
58
82
}
83
+ return tv
84
+ }
85
+
86
+ // typedValue is a value of some specific type.
87
+ type typedValue struct {
88
+ value value.Value
89
+ typeRef schema.TypeRef
90
+ schema * schema.Schema
59
91
}
60
92
61
- // AsValue removes the type from the TypedValue and only keeps the value.
62
- func (tv TypedValue ) AsValue () * value.Value {
93
+ var _ TypedValue = typedValue {}
94
+
95
+ func (tv typedValue ) AsValue () * value.Value {
63
96
return & tv .value
64
97
}
65
98
66
- // Validate returns an error with a list of every spec violation.
67
- func (tv TypedValue ) Validate () error {
99
+ func (tv typedValue ) Validate () error {
68
100
if errs := tv .walker ().validate (); len (errs ) != 0 {
69
101
return errs
70
102
}
71
103
return nil
72
104
}
73
105
74
- // ToFieldSet creates a set containing every leaf field mentioned in tv, or
75
- // validation errors, if any were encountered.
76
- func (tv TypedValue ) ToFieldSet () (* fieldpath.Set , error ) {
106
+ func (tv typedValue ) ToFieldSet () (* fieldpath.Set , error ) {
77
107
s := fieldpath .NewSet ()
78
108
w := tv .walker ()
79
109
w .leafFieldCallback = func (p fieldpath.Path ) { s .Insert (p ) }
@@ -83,73 +113,27 @@ func (tv TypedValue) ToFieldSet() (*fieldpath.Set, error) {
83
113
return s , nil
84
114
}
85
115
86
- // Merge returns the result of merging tv and pso ("partially specified
87
- // object") together. Of note:
88
- // * No fields can be removed by this operation.
89
- // * If both tv and pso specify a given leaf field, the result will keep pso's
90
- // value.
91
- // * Container typed elements will have their items ordered:
92
- // * like tv, if pso doesn't change anything in the container
93
- // * like pso, if pso does change something in the container.
94
- // tv and pso must both be of the same type (their Schema and TypeRef must
95
- // match), or an error will be returned. Validation errors will be returned if
96
- // the objects don't conform to the schema.
97
- func (tv TypedValue ) Merge (pso TypedValue ) (TypedValue , error ) {
98
- return merge (tv , pso , ruleKeepRHS , nil )
99
- }
100
-
101
- // Comparison is the return value of a TypedValue.Compare() operation.
102
- //
103
- // No field will appear in more than one of the three fieldsets. If all of the
104
- // fieldsets are empty, then the objects must have been equal.
105
- type Comparison struct {
106
- // Merged is the result of merging the two objects, as explained in the
107
- // comments on TypedValue.Merge().
108
- Merged TypedValue
109
-
110
- // Removed contains any fields removed by rhs (the right-hand-side
111
- // object in the comparison).
112
- Removed * fieldpath.Set
113
- // Modified contains fields present in both objects but different.
114
- Modified * fieldpath.Set
115
- // Added contains any fields added by rhs.
116
- Added * fieldpath.Set
117
- }
118
-
119
- // IsSame returns true if the comparison returned no changes (the two
120
- // compared objects are similar).
121
- func (c * Comparison ) IsSame () bool {
122
- return c .Removed .Empty () && c .Modified .Empty () && c .Added .Empty ()
123
- }
124
-
125
- // String returns a human readable version of the comparison.
126
- func (c * Comparison ) String () string {
127
- str := fmt .Sprintf ("- Merged Object:\n %v\n " , c .Merged .AsValue ())
128
- if ! c .Modified .Empty () {
129
- str += fmt .Sprintf ("- Modified Fields:\n %v\n " , c .Modified )
130
- }
131
- if ! c .Added .Empty () {
132
- str += fmt .Sprintf ("- Added Fields:\n %v\n " , c .Added )
116
+ func (tv typedValue ) Merge (pso TypedValue ) (TypedValue , error ) {
117
+ tpso , ok := pso .(typedValue )
118
+ if ! ok {
119
+ return nil , errorFormatter {}.
120
+ errorf ("can't merge typedValue with %T" , pso )
133
121
}
134
- if ! c .Removed .Empty () {
135
- str += fmt .Sprintf ("- Removed Fields:\n %v\n " , c .Removed )
136
- }
137
- return str
122
+ return merge (tv , tpso , ruleKeepRHS , nil )
138
123
}
139
124
140
- // Compare compares the two objects. See the comments on the `Comparison`
141
- // struct for details on the return value.
142
- //
143
- // tv and rhs must both be of the same type (their Schema and TypeRef must
144
- // match), or an error will be returned. Validation errors will be returned if
145
- // the objects don't conform to the schema.
146
- func (tv TypedValue ) Compare (rhs TypedValue ) (c * Comparison , err error ) {
125
+ func (tv typedValue ) Compare (rhs TypedValue ) (c * Comparison , err error ) {
126
+ trhs , ok := rhs .(typedValue )
127
+ if ! ok {
128
+ return nil , errorFormatter {}.
129
+ errorf ("can't compare typedValue with %T" , rhs )
130
+ }
147
131
c = & Comparison {
148
132
Removed : fieldpath .NewSet (),
149
133
Modified : fieldpath .NewSet (),
150
134
Added : fieldpath .NewSet (),
151
135
}
152
- c .Merged , err = merge (tv , rhs , func (w * mergingWalker ) {
136
+ c .Merged , err = merge (tv , trhs , func (w * mergingWalker ) {
153
137
if w .lhs == nil {
154
138
c .Added .Insert (w .path )
155
139
} else if w .rhs == nil {
@@ -175,13 +159,13 @@ func (tv TypedValue) Compare(rhs TypedValue) (c *Comparison, err error) {
175
159
return c , nil
176
160
}
177
161
178
- func merge (lhs , rhs TypedValue , rule , postRule mergeRule ) (TypedValue , error ) {
162
+ func merge (lhs , rhs typedValue , rule , postRule mergeRule ) (TypedValue , error ) {
179
163
if lhs .schema != rhs .schema {
180
- return TypedValue {} , errorFormatter {}.
164
+ return nil , errorFormatter {}.
181
165
errorf ("expected objects with types from the same schema" )
182
166
}
183
167
if ! reflect .DeepEqual (lhs .typeRef , rhs .typeRef ) {
184
- return TypedValue {} , errorFormatter {}.
168
+ return nil , errorFormatter {}.
185
169
errorf ("expected objects of the same type, but got %v and %v" , lhs .typeRef , rhs .typeRef )
186
170
}
187
171
@@ -195,10 +179,10 @@ func merge(lhs, rhs TypedValue, rule, postRule mergeRule) (TypedValue, error) {
195
179
}
196
180
errs := mw .merge ()
197
181
if len (errs ) > 0 {
198
- return TypedValue {} , errs
182
+ return nil , errs
199
183
}
200
184
201
- out := TypedValue {
185
+ out := typedValue {
202
186
schema : lhs .schema ,
203
187
typeRef : lhs .typeRef ,
204
188
}
@@ -210,15 +194,41 @@ func merge(lhs, rhs TypedValue, rule, postRule mergeRule) (TypedValue, error) {
210
194
return out , nil
211
195
}
212
196
213
- // AsTypeUnvalidated is just like WithType, but doesn't validate that the type
214
- // conforms to the schema, for cases where that has already been checked or
215
- // where you're going to call a method that validates as a side-effect (like
216
- // ToFieldSet).
217
- func AsTypedUnvalidated (v value.Value , s * schema.Schema , typeName string ) TypedValue {
218
- tv := TypedValue {
219
- value : v ,
220
- typeRef : schema.TypeRef {NamedType : & typeName },
221
- schema : s ,
197
+ // Comparison is the return value of a TypedValue.Compare() operation.
198
+ //
199
+ // No field will appear in more than one of the three fieldsets. If all of the
200
+ // fieldsets are empty, then the objects must have been equal.
201
+ type Comparison struct {
202
+ // Merged is the result of merging the two objects, as explained in the
203
+ // comments on TypedValue.Merge().
204
+ Merged TypedValue
205
+
206
+ // Removed contains any fields removed by rhs (the right-hand-side
207
+ // object in the comparison).
208
+ Removed * fieldpath.Set
209
+ // Modified contains fields present in both objects but different.
210
+ Modified * fieldpath.Set
211
+ // Added contains any fields added by rhs.
212
+ Added * fieldpath.Set
213
+ }
214
+
215
+ // IsSame returns true if the comparison returned no changes (the two
216
+ // compared objects are similar).
217
+ func (c * Comparison ) IsSame () bool {
218
+ return c .Removed .Empty () && c .Modified .Empty () && c .Added .Empty ()
219
+ }
220
+
221
+ // String returns a human readable version of the comparison.
222
+ func (c * Comparison ) String () string {
223
+ str := fmt .Sprintf ("- Merged Object:\n %v\n " , c .Merged .AsValue ())
224
+ if ! c .Modified .Empty () {
225
+ str += fmt .Sprintf ("- Modified Fields:\n %v\n " , c .Modified )
222
226
}
223
- return tv
227
+ if ! c .Added .Empty () {
228
+ str += fmt .Sprintf ("- Added Fields:\n %v\n " , c .Added )
229
+ }
230
+ if ! c .Removed .Empty () {
231
+ str += fmt .Sprintf ("- Removed Fields:\n %v\n " , c .Removed )
232
+ }
233
+ return str
224
234
}
0 commit comments