podman

Форк
0
289 строк · 8.3 Кб
1
// Copyright 2013-2022 Frank Schroeder. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4

5
package properties
6

7
import (
8
	"fmt"
9
	"reflect"
10
	"strconv"
11
	"strings"
12
	"time"
13
)
14

15
// Decode assigns property values to exported fields of a struct.
16
//
17
// Decode traverses v recursively and returns an error if a value cannot be
18
// converted to the field type or a required value is missing for a field.
19
//
20
// The following type dependent decodings are used:
21
//
22
// String, boolean, numeric fields have the value of the property key assigned.
23
// The property key name is the name of the field. A different key and a default
24
// value can be set in the field's tag. Fields without default value are
25
// required. If the value cannot be converted to the field type an error is
26
// returned.
27
//
28
// time.Duration fields have the result of time.ParseDuration() assigned.
29
//
30
// time.Time fields have the vaule of time.Parse() assigned. The default layout
31
// is time.RFC3339 but can be set in the field's tag.
32
//
33
// Arrays and slices of string, boolean, numeric, time.Duration and time.Time
34
// fields have the value interpreted as a comma separated list of values. The
35
// individual values are trimmed of whitespace and empty values are ignored. A
36
// default value can be provided as a semicolon separated list in the field's
37
// tag.
38
//
39
// Struct fields are decoded recursively using the field name plus "." as
40
// prefix. The prefix (without dot) can be overridden in the field's tag.
41
// Default values are not supported in the field's tag. Specify them on the
42
// fields of the inner struct instead.
43
//
44
// Map fields must have a key of type string and are decoded recursively by
45
// using the field's name plus ".' as prefix and the next element of the key
46
// name as map key. The prefix (without dot) can be overridden in the field's
47
// tag. Default values are not supported.
48
//
49
// Examples:
50
//
51
//	// Field is ignored.
52
//	Field int `properties:"-"`
53
//
54
//	// Field is assigned value of 'Field'.
55
//	Field int
56
//
57
//	// Field is assigned value of 'myName'.
58
//	Field int `properties:"myName"`
59
//
60
//	// Field is assigned value of key 'myName' and has a default
61
//	// value 15 if the key does not exist.
62
//	Field int `properties:"myName,default=15"`
63
//
64
//	// Field is assigned value of key 'Field' and has a default
65
//	// value 15 if the key does not exist.
66
//	Field int `properties:",default=15"`
67
//
68
//	// Field is assigned value of key 'date' and the date
69
//	// is in format 2006-01-02
70
//	Field time.Time `properties:"date,layout=2006-01-02"`
71
//
72
//	// Field is assigned the non-empty and whitespace trimmed
73
//	// values of key 'Field' split by commas.
74
//	Field []string
75
//
76
//	// Field is assigned the non-empty and whitespace trimmed
77
//	// values of key 'Field' split by commas and has a default
78
//	// value ["a", "b", "c"] if the key does not exist.
79
//	Field []string `properties:",default=a;b;c"`
80
//
81
//	// Field is decoded recursively with "Field." as key prefix.
82
//	Field SomeStruct
83
//
84
//	// Field is decoded recursively with "myName." as key prefix.
85
//	Field SomeStruct `properties:"myName"`
86
//
87
//	// Field is decoded recursively with "Field." as key prefix
88
//	// and the next dotted element of the key as map key.
89
//	Field map[string]string
90
//
91
//	// Field is decoded recursively with "myName." as key prefix
92
//	// and the next dotted element of the key as map key.
93
//	Field map[string]string `properties:"myName"`
94
func (p *Properties) Decode(x interface{}) error {
95
	t, v := reflect.TypeOf(x), reflect.ValueOf(x)
96
	if t.Kind() != reflect.Ptr || v.Elem().Type().Kind() != reflect.Struct {
97
		return fmt.Errorf("not a pointer to struct: %s", t)
98
	}
99
	if err := dec(p, "", nil, nil, v); err != nil {
100
		return err
101
	}
102
	return nil
103
}
104

105
func dec(p *Properties, key string, def *string, opts map[string]string, v reflect.Value) error {
106
	t := v.Type()
107

108
	// value returns the property value for key or the default if provided.
109
	value := func() (string, error) {
110
		if val, ok := p.Get(key); ok {
111
			return val, nil
112
		}
113
		if def != nil {
114
			return *def, nil
115
		}
116
		return "", fmt.Errorf("missing required key %s", key)
117
	}
118

119
	// conv converts a string to a value of the given type.
120
	conv := func(s string, t reflect.Type) (val reflect.Value, err error) {
121
		var v interface{}
122

123
		switch {
124
		case isDuration(t):
125
			v, err = time.ParseDuration(s)
126

127
		case isTime(t):
128
			layout := opts["layout"]
129
			if layout == "" {
130
				layout = time.RFC3339
131
			}
132
			v, err = time.Parse(layout, s)
133

134
		case isBool(t):
135
			v, err = boolVal(s), nil
136

137
		case isString(t):
138
			v, err = s, nil
139

140
		case isFloat(t):
141
			v, err = strconv.ParseFloat(s, 64)
142

143
		case isInt(t):
144
			v, err = strconv.ParseInt(s, 10, 64)
145

146
		case isUint(t):
147
			v, err = strconv.ParseUint(s, 10, 64)
148

149
		default:
150
			return reflect.Zero(t), fmt.Errorf("unsupported type %s", t)
151
		}
152
		if err != nil {
153
			return reflect.Zero(t), err
154
		}
155
		return reflect.ValueOf(v).Convert(t), nil
156
	}
157

158
	// keydef returns the property key and the default value based on the
159
	// name of the struct field and the options in the tag.
160
	keydef := func(f reflect.StructField) (string, *string, map[string]string) {
161
		_key, _opts := parseTag(f.Tag.Get("properties"))
162

163
		var _def *string
164
		if d, ok := _opts["default"]; ok {
165
			_def = &d
166
		}
167
		if _key != "" {
168
			return _key, _def, _opts
169
		}
170
		return f.Name, _def, _opts
171
	}
172

173
	switch {
174
	case isDuration(t) || isTime(t) || isBool(t) || isString(t) || isFloat(t) || isInt(t) || isUint(t):
175
		s, err := value()
176
		if err != nil {
177
			return err
178
		}
179
		val, err := conv(s, t)
180
		if err != nil {
181
			return err
182
		}
183
		v.Set(val)
184

185
	case isPtr(t):
186
		return dec(p, key, def, opts, v.Elem())
187

188
	case isStruct(t):
189
		for i := 0; i < v.NumField(); i++ {
190
			fv := v.Field(i)
191
			fk, def, opts := keydef(t.Field(i))
192
			if !fv.CanSet() {
193
				return fmt.Errorf("cannot set %s", t.Field(i).Name)
194
			}
195
			if fk == "-" {
196
				continue
197
			}
198
			if key != "" {
199
				fk = key + "." + fk
200
			}
201
			if err := dec(p, fk, def, opts, fv); err != nil {
202
				return err
203
			}
204
		}
205
		return nil
206

207
	case isArray(t):
208
		val, err := value()
209
		if err != nil {
210
			return err
211
		}
212
		vals := split(val, ";")
213
		a := reflect.MakeSlice(t, 0, len(vals))
214
		for _, s := range vals {
215
			val, err := conv(s, t.Elem())
216
			if err != nil {
217
				return err
218
			}
219
			a = reflect.Append(a, val)
220
		}
221
		v.Set(a)
222

223
	case isMap(t):
224
		valT := t.Elem()
225
		m := reflect.MakeMap(t)
226
		for postfix := range p.FilterStripPrefix(key + ".").m {
227
			pp := strings.SplitN(postfix, ".", 2)
228
			mk, mv := pp[0], reflect.New(valT)
229
			if err := dec(p, key+"."+mk, nil, nil, mv); err != nil {
230
				return err
231
			}
232
			m.SetMapIndex(reflect.ValueOf(mk), mv.Elem())
233
		}
234
		v.Set(m)
235

236
	default:
237
		return fmt.Errorf("unsupported type %s", t)
238
	}
239
	return nil
240
}
241

242
// split splits a string on sep, trims whitespace of elements
243
// and omits empty elements
244
func split(s string, sep string) []string {
245
	var a []string
246
	for _, v := range strings.Split(s, sep) {
247
		if v = strings.TrimSpace(v); v != "" {
248
			a = append(a, v)
249
		}
250
	}
251
	return a
252
}
253

254
// parseTag parses a "key,k=v,k=v,..."
255
func parseTag(tag string) (key string, opts map[string]string) {
256
	opts = map[string]string{}
257
	for i, s := range strings.Split(tag, ",") {
258
		if i == 0 {
259
			key = s
260
			continue
261
		}
262

263
		pp := strings.SplitN(s, "=", 2)
264
		if len(pp) == 1 {
265
			opts[pp[0]] = ""
266
		} else {
267
			opts[pp[0]] = pp[1]
268
		}
269
	}
270
	return key, opts
271
}
272

273
func isArray(t reflect.Type) bool    { return t.Kind() == reflect.Array || t.Kind() == reflect.Slice }
274
func isBool(t reflect.Type) bool     { return t.Kind() == reflect.Bool }
275
func isDuration(t reflect.Type) bool { return t == reflect.TypeOf(time.Second) }
276
func isMap(t reflect.Type) bool      { return t.Kind() == reflect.Map }
277
func isPtr(t reflect.Type) bool      { return t.Kind() == reflect.Ptr }
278
func isString(t reflect.Type) bool   { return t.Kind() == reflect.String }
279
func isStruct(t reflect.Type) bool   { return t.Kind() == reflect.Struct }
280
func isTime(t reflect.Type) bool     { return t == reflect.TypeOf(time.Time{}) }
281
func isFloat(t reflect.Type) bool {
282
	return t.Kind() == reflect.Float32 || t.Kind() == reflect.Float64
283
}
284
func isInt(t reflect.Type) bool {
285
	return t.Kind() == reflect.Int || t.Kind() == reflect.Int8 || t.Kind() == reflect.Int16 || t.Kind() == reflect.Int32 || t.Kind() == reflect.Int64
286
}
287
func isUint(t reflect.Type) bool {
288
	return t.Kind() == reflect.Uint || t.Kind() == reflect.Uint8 || t.Kind() == reflect.Uint16 || t.Kind() == reflect.Uint32 || t.Kind() == reflect.Uint64
289
}
290

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

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

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

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