Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / github.com / go-openapi / jsonpointer / pointer.go
1 // Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //   http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // author       sigu-399
16 // author-github  https://github.com/sigu-399
17 // author-mail    sigu.399@gmail.com
18 //
19 // repository-name  jsonpointer
20 // repository-desc  An implementation of JSON Pointer - Go language
21 //
22 // description    Main and unique file.
23 //
24 // created        25-02-2013
25
26 package jsonpointer
27
28 import (
29         "errors"
30         "fmt"
31         "reflect"
32         "strconv"
33         "strings"
34
35         "github.com/go-openapi/swag"
36 )
37
38 const (
39         emptyPointer     = ``
40         pointerSeparator = `/`
41
42         invalidStart = `JSON pointer must be empty or start with a "` + pointerSeparator
43 )
44
45 var jsonPointableType = reflect.TypeOf(new(JSONPointable)).Elem()
46 var jsonSetableType = reflect.TypeOf(new(JSONSetable)).Elem()
47
48 // JSONPointable is an interface for structs to implement when they need to customize the
49 // json pointer process
50 type JSONPointable interface {
51         JSONLookup(string) (interface{}, error)
52 }
53
54 // JSONSetable is an interface for structs to implement when they need to customize the
55 // json pointer process
56 type JSONSetable interface {
57         JSONSet(string, interface{}) error
58 }
59
60 // New creates a new json pointer for the given string
61 func New(jsonPointerString string) (Pointer, error) {
62
63         var p Pointer
64         err := p.parse(jsonPointerString)
65         return p, err
66
67 }
68
69 // Pointer the json pointer reprsentation
70 type Pointer struct {
71         referenceTokens []string
72 }
73
74 // "Constructor", parses the given string JSON pointer
75 func (p *Pointer) parse(jsonPointerString string) error {
76
77         var err error
78
79         if jsonPointerString != emptyPointer {
80                 if !strings.HasPrefix(jsonPointerString, pointerSeparator) {
81                         err = errors.New(invalidStart)
82                 } else {
83                         referenceTokens := strings.Split(jsonPointerString, pointerSeparator)
84                         for _, referenceToken := range referenceTokens[1:] {
85                                 p.referenceTokens = append(p.referenceTokens, referenceToken)
86                         }
87                 }
88         }
89
90         return err
91 }
92
93 // Get uses the pointer to retrieve a value from a JSON document
94 func (p *Pointer) Get(document interface{}) (interface{}, reflect.Kind, error) {
95         return p.get(document, swag.DefaultJSONNameProvider)
96 }
97
98 // Set uses the pointer to set a value from a JSON document
99 func (p *Pointer) Set(document interface{}, value interface{}) (interface{}, error) {
100         return document, p.set(document, value, swag.DefaultJSONNameProvider)
101 }
102
103 // GetForToken gets a value for a json pointer token 1 level deep
104 func GetForToken(document interface{}, decodedToken string) (interface{}, reflect.Kind, error) {
105         return getSingleImpl(document, decodedToken, swag.DefaultJSONNameProvider)
106 }
107
108 // SetForToken gets a value for a json pointer token 1 level deep
109 func SetForToken(document interface{}, decodedToken string, value interface{}) (interface{}, error) {
110         return document, setSingleImpl(document, value, decodedToken, swag.DefaultJSONNameProvider)
111 }
112
113 func getSingleImpl(node interface{}, decodedToken string, nameProvider *swag.NameProvider) (interface{}, reflect.Kind, error) {
114         rValue := reflect.Indirect(reflect.ValueOf(node))
115         kind := rValue.Kind()
116
117         switch kind {
118
119         case reflect.Struct:
120                 if rValue.Type().Implements(jsonPointableType) {
121                         r, err := node.(JSONPointable).JSONLookup(decodedToken)
122                         if err != nil {
123                                 return nil, kind, err
124                         }
125                         return r, kind, nil
126                 }
127                 nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
128                 if !ok {
129                         return nil, kind, fmt.Errorf("object has no field %q", decodedToken)
130                 }
131                 fld := rValue.FieldByName(nm)
132                 return fld.Interface(), kind, nil
133
134         case reflect.Map:
135                 kv := reflect.ValueOf(decodedToken)
136                 mv := rValue.MapIndex(kv)
137
138                 if mv.IsValid() && !swag.IsZero(mv) {
139                         return mv.Interface(), kind, nil
140                 }
141                 return nil, kind, fmt.Errorf("object has no key %q", decodedToken)
142
143         case reflect.Slice:
144                 tokenIndex, err := strconv.Atoi(decodedToken)
145                 if err != nil {
146                         return nil, kind, err
147                 }
148                 sLength := rValue.Len()
149                 if tokenIndex < 0 || tokenIndex >= sLength {
150                         return nil, kind, fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength-1, tokenIndex)
151                 }
152
153                 elem := rValue.Index(tokenIndex)
154                 return elem.Interface(), kind, nil
155
156         default:
157                 return nil, kind, fmt.Errorf("invalid token reference %q", decodedToken)
158         }
159
160 }
161
162 func setSingleImpl(node, data interface{}, decodedToken string, nameProvider *swag.NameProvider) error {
163         rValue := reflect.Indirect(reflect.ValueOf(node))
164         switch rValue.Kind() {
165
166         case reflect.Struct:
167                 if ns, ok := node.(JSONSetable); ok { // pointer impl
168                         return ns.JSONSet(decodedToken, data)
169                 }
170
171                 if rValue.Type().Implements(jsonSetableType) {
172                         return node.(JSONSetable).JSONSet(decodedToken, data)
173                 }
174
175                 nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
176                 if !ok {
177                         return fmt.Errorf("object has no field %q", decodedToken)
178                 }
179                 fld := rValue.FieldByName(nm)
180                 if fld.IsValid() {
181                         fld.Set(reflect.ValueOf(data))
182                 }
183                 return nil
184
185         case reflect.Map:
186                 kv := reflect.ValueOf(decodedToken)
187                 rValue.SetMapIndex(kv, reflect.ValueOf(data))
188                 return nil
189
190         case reflect.Slice:
191                 tokenIndex, err := strconv.Atoi(decodedToken)
192                 if err != nil {
193                         return err
194                 }
195                 sLength := rValue.Len()
196                 if tokenIndex < 0 || tokenIndex >= sLength {
197                         return fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength, tokenIndex)
198                 }
199
200                 elem := rValue.Index(tokenIndex)
201                 if !elem.CanSet() {
202                         return fmt.Errorf("can't set slice index %s to %v", decodedToken, data)
203                 }
204                 elem.Set(reflect.ValueOf(data))
205                 return nil
206
207         default:
208                 return fmt.Errorf("invalid token reference %q", decodedToken)
209         }
210
211 }
212
213 func (p *Pointer) get(node interface{}, nameProvider *swag.NameProvider) (interface{}, reflect.Kind, error) {
214
215         if nameProvider == nil {
216                 nameProvider = swag.DefaultJSONNameProvider
217         }
218
219         kind := reflect.Invalid
220
221         // Full document when empty
222         if len(p.referenceTokens) == 0 {
223                 return node, kind, nil
224         }
225
226         for _, token := range p.referenceTokens {
227
228                 decodedToken := Unescape(token)
229
230                 r, knd, err := getSingleImpl(node, decodedToken, nameProvider)
231                 if err != nil {
232                         return nil, knd, err
233                 }
234                 node, kind = r, knd
235
236         }
237
238         rValue := reflect.ValueOf(node)
239         kind = rValue.Kind()
240
241         return node, kind, nil
242 }
243
244 func (p *Pointer) set(node, data interface{}, nameProvider *swag.NameProvider) error {
245         knd := reflect.ValueOf(node).Kind()
246
247         if knd != reflect.Ptr && knd != reflect.Struct && knd != reflect.Map && knd != reflect.Slice && knd != reflect.Array {
248                 return fmt.Errorf("only structs, pointers, maps and slices are supported for setting values")
249         }
250
251         if nameProvider == nil {
252                 nameProvider = swag.DefaultJSONNameProvider
253         }
254
255         // Full document when empty
256         if len(p.referenceTokens) == 0 {
257                 return nil
258         }
259
260         lastI := len(p.referenceTokens) - 1
261         for i, token := range p.referenceTokens {
262                 isLastToken := i == lastI
263                 decodedToken := Unescape(token)
264
265                 if isLastToken {
266
267                         return setSingleImpl(node, data, decodedToken, nameProvider)
268                 }
269
270                 rValue := reflect.Indirect(reflect.ValueOf(node))
271                 kind := rValue.Kind()
272
273                 switch kind {
274
275                 case reflect.Struct:
276                         if rValue.Type().Implements(jsonPointableType) {
277                                 r, err := node.(JSONPointable).JSONLookup(decodedToken)
278                                 if err != nil {
279                                         return err
280                                 }
281                                 fld := reflect.ValueOf(r)
282                                 if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr {
283                                         node = fld.Addr().Interface()
284                                         continue
285                                 }
286                                 node = r
287                                 continue
288                         }
289                         nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
290                         if !ok {
291                                 return fmt.Errorf("object has no field %q", decodedToken)
292                         }
293                         fld := rValue.FieldByName(nm)
294                         if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr {
295                                 node = fld.Addr().Interface()
296                                 continue
297                         }
298                         node = fld.Interface()
299
300                 case reflect.Map:
301                         kv := reflect.ValueOf(decodedToken)
302                         mv := rValue.MapIndex(kv)
303
304                         if !mv.IsValid() {
305                                 return fmt.Errorf("object has no key %q", decodedToken)
306                         }
307                         if mv.CanAddr() && mv.Kind() != reflect.Interface && mv.Kind() != reflect.Map && mv.Kind() != reflect.Slice && mv.Kind() != reflect.Ptr {
308                                 node = mv.Addr().Interface()
309                                 continue
310                         }
311                         node = mv.Interface()
312
313                 case reflect.Slice:
314                         tokenIndex, err := strconv.Atoi(decodedToken)
315                         if err != nil {
316                                 return err
317                         }
318                         sLength := rValue.Len()
319                         if tokenIndex < 0 || tokenIndex >= sLength {
320                                 return fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength, tokenIndex)
321                         }
322
323                         elem := rValue.Index(tokenIndex)
324                         if elem.CanAddr() && elem.Kind() != reflect.Interface && elem.Kind() != reflect.Map && elem.Kind() != reflect.Slice && elem.Kind() != reflect.Ptr {
325                                 node = elem.Addr().Interface()
326                                 continue
327                         }
328                         node = elem.Interface()
329
330                 default:
331                         return fmt.Errorf("invalid token reference %q", decodedToken)
332                 }
333
334         }
335
336         return nil
337 }
338
339 // DecodedTokens returns the decoded tokens
340 func (p *Pointer) DecodedTokens() []string {
341         result := make([]string, 0, len(p.referenceTokens))
342         for _, t := range p.referenceTokens {
343                 result = append(result, Unescape(t))
344         }
345         return result
346 }
347
348 // IsEmpty returns true if this is an empty json pointer
349 // this indicates that it points to the root document
350 func (p *Pointer) IsEmpty() bool {
351         return len(p.referenceTokens) == 0
352 }
353
354 // Pointer to string representation function
355 func (p *Pointer) String() string {
356
357         if len(p.referenceTokens) == 0 {
358                 return emptyPointer
359         }
360
361         pointerString := pointerSeparator + strings.Join(p.referenceTokens, pointerSeparator)
362
363         return pointerString
364 }
365
366 // Specific JSON pointer encoding here
367 // ~0 => ~
368 // ~1 => /
369 // ... and vice versa
370
371 const (
372         encRefTok0 = `~0`
373         encRefTok1 = `~1`
374         decRefTok0 = `~`
375         decRefTok1 = `/`
376 )
377
378 // Unescape unescapes a json pointer reference token string to the original representation
379 func Unescape(token string) string {
380         step1 := strings.Replace(token, encRefTok1, decRefTok1, -1)
381         step2 := strings.Replace(step1, encRefTok0, decRefTok0, -1)
382         return step2
383 }
384
385 // Escape escapes a pointer reference token string
386 func Escape(token string) string {
387         step1 := strings.Replace(token, decRefTok0, encRefTok0, -1)
388         step2 := strings.Replace(step1, decRefTok1, encRefTok1, -1)
389         return step2
390 }