podman

Форк
0
602 строки · 16.4 Кб
1
package toml
2

3
import (
4
	"bytes"
5
	"encoding"
6
	"encoding/json"
7
	"fmt"
8
	"io"
9
	"io/ioutil"
10
	"math"
11
	"os"
12
	"reflect"
13
	"strconv"
14
	"strings"
15
	"time"
16
)
17

18
// Unmarshaler is the interface implemented by objects that can unmarshal a
19
// TOML description of themselves.
20
type Unmarshaler interface {
21
	UnmarshalTOML(interface{}) error
22
}
23

24
// Unmarshal decodes the contents of data in TOML format into a pointer v.
25
//
26
// See [Decoder] for a description of the decoding process.
27
func Unmarshal(data []byte, v interface{}) error {
28
	_, err := NewDecoder(bytes.NewReader(data)).Decode(v)
29
	return err
30
}
31

32
// Decode the TOML data in to the pointer v.
33
//
34
// See [Decoder] for a description of the decoding process.
35
func Decode(data string, v interface{}) (MetaData, error) {
36
	return NewDecoder(strings.NewReader(data)).Decode(v)
37
}
38

39
// DecodeFile reads the contents of a file and decodes it with [Decode].
40
func DecodeFile(path string, v interface{}) (MetaData, error) {
41
	fp, err := os.Open(path)
42
	if err != nil {
43
		return MetaData{}, err
44
	}
45
	defer fp.Close()
46
	return NewDecoder(fp).Decode(v)
47
}
48

49
// Primitive is a TOML value that hasn't been decoded into a Go value.
50
//
51
// This type can be used for any value, which will cause decoding to be delayed.
52
// You can use [PrimitiveDecode] to "manually" decode these values.
53
//
54
// NOTE: The underlying representation of a `Primitive` value is subject to
55
// change. Do not rely on it.
56
//
57
// NOTE: Primitive values are still parsed, so using them will only avoid the
58
// overhead of reflection. They can be useful when you don't know the exact type
59
// of TOML data until runtime.
60
type Primitive struct {
61
	undecoded interface{}
62
	context   Key
63
}
64

65
// The significand precision for float32 and float64 is 24 and 53 bits; this is
66
// the range a natural number can be stored in a float without loss of data.
67
const (
68
	maxSafeFloat32Int = 16777215                // 2^24-1
69
	maxSafeFloat64Int = int64(9007199254740991) // 2^53-1
70
)
71

72
// Decoder decodes TOML data.
73
//
74
// TOML tables correspond to Go structs or maps; they can be used
75
// interchangeably, but structs offer better type safety.
76
//
77
// TOML table arrays correspond to either a slice of structs or a slice of maps.
78
//
79
// TOML datetimes correspond to [time.Time]. Local datetimes are parsed in the
80
// local timezone.
81
//
82
// [time.Duration] types are treated as nanoseconds if the TOML value is an
83
// integer, or they're parsed with time.ParseDuration() if they're strings.
84
//
85
// All other TOML types (float, string, int, bool and array) correspond to the
86
// obvious Go types.
87
//
88
// An exception to the above rules is if a type implements the TextUnmarshaler
89
// interface, in which case any primitive TOML value (floats, strings, integers,
90
// booleans, datetimes) will be converted to a []byte and given to the value's
91
// UnmarshalText method. See the Unmarshaler example for a demonstration with
92
// email addresses.
93
//
94
// # Key mapping
95
//
96
// TOML keys can map to either keys in a Go map or field names in a Go struct.
97
// The special `toml` struct tag can be used to map TOML keys to struct fields
98
// that don't match the key name exactly (see the example). A case insensitive
99
// match to struct names will be tried if an exact match can't be found.
100
//
101
// The mapping between TOML values and Go values is loose. That is, there may
102
// exist TOML values that cannot be placed into your representation, and there
103
// may be parts of your representation that do not correspond to TOML values.
104
// This loose mapping can be made stricter by using the IsDefined and/or
105
// Undecoded methods on the MetaData returned.
106
//
107
// This decoder does not handle cyclic types. Decode will not terminate if a
108
// cyclic type is passed.
109
type Decoder struct {
110
	r io.Reader
111
}
112

113
// NewDecoder creates a new Decoder.
114
func NewDecoder(r io.Reader) *Decoder {
115
	return &Decoder{r: r}
116
}
117

118
var (
119
	unmarshalToml = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
120
	unmarshalText = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
121
	primitiveType = reflect.TypeOf((*Primitive)(nil)).Elem()
122
)
123

124
// Decode TOML data in to the pointer `v`.
125
func (dec *Decoder) Decode(v interface{}) (MetaData, error) {
126
	rv := reflect.ValueOf(v)
127
	if rv.Kind() != reflect.Ptr {
128
		s := "%q"
129
		if reflect.TypeOf(v) == nil {
130
			s = "%v"
131
		}
132

133
		return MetaData{}, fmt.Errorf("toml: cannot decode to non-pointer "+s, reflect.TypeOf(v))
134
	}
135
	if rv.IsNil() {
136
		return MetaData{}, fmt.Errorf("toml: cannot decode to nil value of %q", reflect.TypeOf(v))
137
	}
138

139
	// Check if this is a supported type: struct, map, interface{}, or something
140
	// that implements UnmarshalTOML or UnmarshalText.
141
	rv = indirect(rv)
142
	rt := rv.Type()
143
	if rv.Kind() != reflect.Struct && rv.Kind() != reflect.Map &&
144
		!(rv.Kind() == reflect.Interface && rv.NumMethod() == 0) &&
145
		!rt.Implements(unmarshalToml) && !rt.Implements(unmarshalText) {
146
		return MetaData{}, fmt.Errorf("toml: cannot decode to type %s", rt)
147
	}
148

149
	// TODO: parser should read from io.Reader? Or at the very least, make it
150
	// read from []byte rather than string
151
	data, err := ioutil.ReadAll(dec.r)
152
	if err != nil {
153
		return MetaData{}, err
154
	}
155

156
	p, err := parse(string(data))
157
	if err != nil {
158
		return MetaData{}, err
159
	}
160

161
	md := MetaData{
162
		mapping: p.mapping,
163
		keyInfo: p.keyInfo,
164
		keys:    p.ordered,
165
		decoded: make(map[string]struct{}, len(p.ordered)),
166
		context: nil,
167
		data:    data,
168
	}
169
	return md, md.unify(p.mapping, rv)
170
}
171

172
// PrimitiveDecode is just like the other Decode* functions, except it decodes a
173
// TOML value that has already been parsed. Valid primitive values can *only* be
174
// obtained from values filled by the decoder functions, including this method.
175
// (i.e., v may contain more [Primitive] values.)
176
//
177
// Meta data for primitive values is included in the meta data returned by the
178
// Decode* functions with one exception: keys returned by the Undecoded method
179
// will only reflect keys that were decoded. Namely, any keys hidden behind a
180
// Primitive will be considered undecoded. Executing this method will update the
181
// undecoded keys in the meta data. (See the example.)
182
func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error {
183
	md.context = primValue.context
184
	defer func() { md.context = nil }()
185
	return md.unify(primValue.undecoded, rvalue(v))
186
}
187

188
// unify performs a sort of type unification based on the structure of `rv`,
189
// which is the client representation.
190
//
191
// Any type mismatch produces an error. Finding a type that we don't know
192
// how to handle produces an unsupported type error.
193
func (md *MetaData) unify(data interface{}, rv reflect.Value) error {
194
	// Special case. Look for a `Primitive` value.
195
	// TODO: #76 would make this superfluous after implemented.
196
	if rv.Type() == primitiveType {
197
		// Save the undecoded data and the key context into the primitive
198
		// value.
199
		context := make(Key, len(md.context))
200
		copy(context, md.context)
201
		rv.Set(reflect.ValueOf(Primitive{
202
			undecoded: data,
203
			context:   context,
204
		}))
205
		return nil
206
	}
207

208
	rvi := rv.Interface()
209
	if v, ok := rvi.(Unmarshaler); ok {
210
		return v.UnmarshalTOML(data)
211
	}
212
	if v, ok := rvi.(encoding.TextUnmarshaler); ok {
213
		return md.unifyText(data, v)
214
	}
215

216
	// TODO:
217
	// The behavior here is incorrect whenever a Go type satisfies the
218
	// encoding.TextUnmarshaler interface but also corresponds to a TOML hash or
219
	// array. In particular, the unmarshaler should only be applied to primitive
220
	// TOML values. But at this point, it will be applied to all kinds of values
221
	// and produce an incorrect error whenever those values are hashes or arrays
222
	// (including arrays of tables).
223

224
	k := rv.Kind()
225

226
	if k >= reflect.Int && k <= reflect.Uint64 {
227
		return md.unifyInt(data, rv)
228
	}
229
	switch k {
230
	case reflect.Ptr:
231
		elem := reflect.New(rv.Type().Elem())
232
		err := md.unify(data, reflect.Indirect(elem))
233
		if err != nil {
234
			return err
235
		}
236
		rv.Set(elem)
237
		return nil
238
	case reflect.Struct:
239
		return md.unifyStruct(data, rv)
240
	case reflect.Map:
241
		return md.unifyMap(data, rv)
242
	case reflect.Array:
243
		return md.unifyArray(data, rv)
244
	case reflect.Slice:
245
		return md.unifySlice(data, rv)
246
	case reflect.String:
247
		return md.unifyString(data, rv)
248
	case reflect.Bool:
249
		return md.unifyBool(data, rv)
250
	case reflect.Interface:
251
		if rv.NumMethod() > 0 { /// Only empty interfaces are supported.
252
			return md.e("unsupported type %s", rv.Type())
253
		}
254
		return md.unifyAnything(data, rv)
255
	case reflect.Float32, reflect.Float64:
256
		return md.unifyFloat64(data, rv)
257
	}
258
	return md.e("unsupported type %s", rv.Kind())
259
}
260

261
func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error {
262
	tmap, ok := mapping.(map[string]interface{})
263
	if !ok {
264
		if mapping == nil {
265
			return nil
266
		}
267
		return md.e("type mismatch for %s: expected table but found %T",
268
			rv.Type().String(), mapping)
269
	}
270

271
	for key, datum := range tmap {
272
		var f *field
273
		fields := cachedTypeFields(rv.Type())
274
		for i := range fields {
275
			ff := &fields[i]
276
			if ff.name == key {
277
				f = ff
278
				break
279
			}
280
			if f == nil && strings.EqualFold(ff.name, key) {
281
				f = ff
282
			}
283
		}
284
		if f != nil {
285
			subv := rv
286
			for _, i := range f.index {
287
				subv = indirect(subv.Field(i))
288
			}
289

290
			if isUnifiable(subv) {
291
				md.decoded[md.context.add(key).String()] = struct{}{}
292
				md.context = append(md.context, key)
293

294
				err := md.unify(datum, subv)
295
				if err != nil {
296
					return err
297
				}
298
				md.context = md.context[0 : len(md.context)-1]
299
			} else if f.name != "" {
300
				return md.e("cannot write unexported field %s.%s", rv.Type().String(), f.name)
301
			}
302
		}
303
	}
304
	return nil
305
}
306

307
func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error {
308
	keyType := rv.Type().Key().Kind()
309
	if keyType != reflect.String && keyType != reflect.Interface {
310
		return fmt.Errorf("toml: cannot decode to a map with non-string key type (%s in %q)",
311
			keyType, rv.Type())
312
	}
313

314
	tmap, ok := mapping.(map[string]interface{})
315
	if !ok {
316
		if tmap == nil {
317
			return nil
318
		}
319
		return md.badtype("map", mapping)
320
	}
321
	if rv.IsNil() {
322
		rv.Set(reflect.MakeMap(rv.Type()))
323
	}
324
	for k, v := range tmap {
325
		md.decoded[md.context.add(k).String()] = struct{}{}
326
		md.context = append(md.context, k)
327

328
		rvval := reflect.Indirect(reflect.New(rv.Type().Elem()))
329

330
		err := md.unify(v, indirect(rvval))
331
		if err != nil {
332
			return err
333
		}
334
		md.context = md.context[0 : len(md.context)-1]
335

336
		rvkey := indirect(reflect.New(rv.Type().Key()))
337

338
		switch keyType {
339
		case reflect.Interface:
340
			rvkey.Set(reflect.ValueOf(k))
341
		case reflect.String:
342
			rvkey.SetString(k)
343
		}
344

345
		rv.SetMapIndex(rvkey, rvval)
346
	}
347
	return nil
348
}
349

350
func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error {
351
	datav := reflect.ValueOf(data)
352
	if datav.Kind() != reflect.Slice {
353
		if !datav.IsValid() {
354
			return nil
355
		}
356
		return md.badtype("slice", data)
357
	}
358
	if l := datav.Len(); l != rv.Len() {
359
		return md.e("expected array length %d; got TOML array of length %d", rv.Len(), l)
360
	}
361
	return md.unifySliceArray(datav, rv)
362
}
363

364
func (md *MetaData) unifySlice(data interface{}, rv reflect.Value) error {
365
	datav := reflect.ValueOf(data)
366
	if datav.Kind() != reflect.Slice {
367
		if !datav.IsValid() {
368
			return nil
369
		}
370
		return md.badtype("slice", data)
371
	}
372
	n := datav.Len()
373
	if rv.IsNil() || rv.Cap() < n {
374
		rv.Set(reflect.MakeSlice(rv.Type(), n, n))
375
	}
376
	rv.SetLen(n)
377
	return md.unifySliceArray(datav, rv)
378
}
379

380
func (md *MetaData) unifySliceArray(data, rv reflect.Value) error {
381
	l := data.Len()
382
	for i := 0; i < l; i++ {
383
		err := md.unify(data.Index(i).Interface(), indirect(rv.Index(i)))
384
		if err != nil {
385
			return err
386
		}
387
	}
388
	return nil
389
}
390

391
func (md *MetaData) unifyString(data interface{}, rv reflect.Value) error {
392
	_, ok := rv.Interface().(json.Number)
393
	if ok {
394
		if i, ok := data.(int64); ok {
395
			rv.SetString(strconv.FormatInt(i, 10))
396
		} else if f, ok := data.(float64); ok {
397
			rv.SetString(strconv.FormatFloat(f, 'f', -1, 64))
398
		} else {
399
			return md.badtype("string", data)
400
		}
401
		return nil
402
	}
403

404
	if s, ok := data.(string); ok {
405
		rv.SetString(s)
406
		return nil
407
	}
408
	return md.badtype("string", data)
409
}
410

411
func (md *MetaData) unifyFloat64(data interface{}, rv reflect.Value) error {
412
	rvk := rv.Kind()
413

414
	if num, ok := data.(float64); ok {
415
		switch rvk {
416
		case reflect.Float32:
417
			if num < -math.MaxFloat32 || num > math.MaxFloat32 {
418
				return md.parseErr(errParseRange{i: num, size: rvk.String()})
419
			}
420
			fallthrough
421
		case reflect.Float64:
422
			rv.SetFloat(num)
423
		default:
424
			panic("bug")
425
		}
426
		return nil
427
	}
428

429
	if num, ok := data.(int64); ok {
430
		if (rvk == reflect.Float32 && (num < -maxSafeFloat32Int || num > maxSafeFloat32Int)) ||
431
			(rvk == reflect.Float64 && (num < -maxSafeFloat64Int || num > maxSafeFloat64Int)) {
432
			return md.parseErr(errParseRange{i: num, size: rvk.String()})
433
		}
434
		rv.SetFloat(float64(num))
435
		return nil
436
	}
437

438
	return md.badtype("float", data)
439
}
440

441
func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error {
442
	_, ok := rv.Interface().(time.Duration)
443
	if ok {
444
		// Parse as string duration, and fall back to regular integer parsing
445
		// (as nanosecond) if this is not a string.
446
		if s, ok := data.(string); ok {
447
			dur, err := time.ParseDuration(s)
448
			if err != nil {
449
				return md.parseErr(errParseDuration{s})
450
			}
451
			rv.SetInt(int64(dur))
452
			return nil
453
		}
454
	}
455

456
	num, ok := data.(int64)
457
	if !ok {
458
		return md.badtype("integer", data)
459
	}
460

461
	rvk := rv.Kind()
462
	switch {
463
	case rvk >= reflect.Int && rvk <= reflect.Int64:
464
		if (rvk == reflect.Int8 && (num < math.MinInt8 || num > math.MaxInt8)) ||
465
			(rvk == reflect.Int16 && (num < math.MinInt16 || num > math.MaxInt16)) ||
466
			(rvk == reflect.Int32 && (num < math.MinInt32 || num > math.MaxInt32)) {
467
			return md.parseErr(errParseRange{i: num, size: rvk.String()})
468
		}
469
		rv.SetInt(num)
470
	case rvk >= reflect.Uint && rvk <= reflect.Uint64:
471
		unum := uint64(num)
472
		if rvk == reflect.Uint8 && (num < 0 || unum > math.MaxUint8) ||
473
			rvk == reflect.Uint16 && (num < 0 || unum > math.MaxUint16) ||
474
			rvk == reflect.Uint32 && (num < 0 || unum > math.MaxUint32) {
475
			return md.parseErr(errParseRange{i: num, size: rvk.String()})
476
		}
477
		rv.SetUint(unum)
478
	default:
479
		panic("unreachable")
480
	}
481
	return nil
482
}
483

484
func (md *MetaData) unifyBool(data interface{}, rv reflect.Value) error {
485
	if b, ok := data.(bool); ok {
486
		rv.SetBool(b)
487
		return nil
488
	}
489
	return md.badtype("boolean", data)
490
}
491

492
func (md *MetaData) unifyAnything(data interface{}, rv reflect.Value) error {
493
	rv.Set(reflect.ValueOf(data))
494
	return nil
495
}
496

497
func (md *MetaData) unifyText(data interface{}, v encoding.TextUnmarshaler) error {
498
	var s string
499
	switch sdata := data.(type) {
500
	case Marshaler:
501
		text, err := sdata.MarshalTOML()
502
		if err != nil {
503
			return err
504
		}
505
		s = string(text)
506
	case encoding.TextMarshaler:
507
		text, err := sdata.MarshalText()
508
		if err != nil {
509
			return err
510
		}
511
		s = string(text)
512
	case fmt.Stringer:
513
		s = sdata.String()
514
	case string:
515
		s = sdata
516
	case bool:
517
		s = fmt.Sprintf("%v", sdata)
518
	case int64:
519
		s = fmt.Sprintf("%d", sdata)
520
	case float64:
521
		s = fmt.Sprintf("%f", sdata)
522
	default:
523
		return md.badtype("primitive (string-like)", data)
524
	}
525
	if err := v.UnmarshalText([]byte(s)); err != nil {
526
		return err
527
	}
528
	return nil
529
}
530

531
func (md *MetaData) badtype(dst string, data interface{}) error {
532
	return md.e("incompatible types: TOML value has type %T; destination has type %s", data, dst)
533
}
534

535
func (md *MetaData) parseErr(err error) error {
536
	k := md.context.String()
537
	return ParseError{
538
		LastKey:  k,
539
		Position: md.keyInfo[k].pos,
540
		Line:     md.keyInfo[k].pos.Line,
541
		err:      err,
542
		input:    string(md.data),
543
	}
544
}
545

546
func (md *MetaData) e(format string, args ...interface{}) error {
547
	f := "toml: "
548
	if len(md.context) > 0 {
549
		f = fmt.Sprintf("toml: (last key %q): ", md.context)
550
		p := md.keyInfo[md.context.String()].pos
551
		if p.Line > 0 {
552
			f = fmt.Sprintf("toml: line %d (last key %q): ", p.Line, md.context)
553
		}
554
	}
555
	return fmt.Errorf(f+format, args...)
556
}
557

558
// rvalue returns a reflect.Value of `v`. All pointers are resolved.
559
func rvalue(v interface{}) reflect.Value {
560
	return indirect(reflect.ValueOf(v))
561
}
562

563
// indirect returns the value pointed to by a pointer.
564
//
565
// Pointers are followed until the value is not a pointer. New values are
566
// allocated for each nil pointer.
567
//
568
// An exception to this rule is if the value satisfies an interface of interest
569
// to us (like encoding.TextUnmarshaler).
570
func indirect(v reflect.Value) reflect.Value {
571
	if v.Kind() != reflect.Ptr {
572
		if v.CanSet() {
573
			pv := v.Addr()
574
			pvi := pv.Interface()
575
			if _, ok := pvi.(encoding.TextUnmarshaler); ok {
576
				return pv
577
			}
578
			if _, ok := pvi.(Unmarshaler); ok {
579
				return pv
580
			}
581
		}
582
		return v
583
	}
584
	if v.IsNil() {
585
		v.Set(reflect.New(v.Type().Elem()))
586
	}
587
	return indirect(reflect.Indirect(v))
588
}
589

590
func isUnifiable(rv reflect.Value) bool {
591
	if rv.CanSet() {
592
		return true
593
	}
594
	rvi := rv.Interface()
595
	if _, ok := rvi.(encoding.TextUnmarshaler); ok {
596
		return true
597
	}
598
	if _, ok := rvi.(Unmarshaler); ok {
599
		return true
600
	}
601
	return false
602
}
603

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

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

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

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