podman

Форк
0
390 строк · 10.4 Кб
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
	if rValue.Type().Implements(jsonPointableType) {
118
		r, err := node.(JSONPointable).JSONLookup(decodedToken)
119
		if err != nil {
120
			return nil, kind, err
121
		}
122
		return r, kind, nil
123
	}
124

125
	switch kind {
126
	case reflect.Struct:
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() {
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

165
	if ns, ok := node.(JSONSetable); ok { // pointer impl
166
		return ns.JSONSet(decodedToken, data)
167
	}
168

169
	if rValue.Type().Implements(jsonSetableType) {
170
		return node.(JSONSetable).JSONSet(decodedToken, data)
171
	}
172

173
	switch rValue.Kind() {
174
	case reflect.Struct:
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
		if rValue.Type().Implements(jsonPointableType) {
274
			r, err := node.(JSONPointable).JSONLookup(decodedToken)
275
			if err != nil {
276
				return err
277
			}
278
			fld := reflect.ValueOf(r)
279
			if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr {
280
				node = fld.Addr().Interface()
281
				continue
282
			}
283
			node = r
284
			continue
285
		}
286

287
		switch kind {
288
		case reflect.Struct:
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
}
391

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.