~rogpeppe/juju-core/438-local-instance-Addresses

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
package schema

import (
	"fmt"
	"os"
	"reflect"
	"regexp"
	"strconv"
	"strings"
)

// All map types used in the schema package are of type MapType.
type MapType map[interface{}]interface{}

// All the slice types generated in the schema package are of type ListType.
type ListType []interface{}

// The Coerce method of the Checker interface is called recursively when
// v is being validated.  If err is nil, newv is used as the new value
// at the recursion point.  If err is non-nil, v is taken as invalid and
// may be either ignored or error out depending on where in the schema
// checking process the error happened. Checkers like OneOf may continue
// with an alternative, for instance.
type Checker interface {
	Coerce(v interface{}, path []string) (newv interface{}, err os.Error)
}

type error struct {
	want string
	got interface{}
	path    []string
}

func (e error) String() string {
	var path string
	if e.path[0] == "." {
		path = strings.Join(e.path[1:], "")
	} else {
		path = strings.Join(e.path, "")
	}
	if e.want == "" {
		return fmt.Sprintf("%s: unsupported value", path)
	}
	if e.got == nil {
		return fmt.Sprintf("%s: expected %s, got nothing", path, e.want)
	}
	return fmt.Sprintf("%s: expected %s, got %#v", path, e.want, e.got)
}

// Any returns a Checker that succeeds with any input value and
// results in the value itself unprocessed.
func Any() Checker {
	return anyC{}
}

type anyC struct{}

func (c anyC) Coerce(v interface{}, path []string) (interface{}, os.Error) {
	return v, nil
}


// Const returns a Checker that only succeeds if the input matches
// value exactly.  The value is compared with reflect.DeepEqual.
func Const(value interface{}) Checker {
	return constC{value}
}

type constC struct {
	value interface{}
}

func (c constC) Coerce(v interface{}, path []string) (interface{}, os.Error) {
	if reflect.DeepEqual(v, c.value) {
		return v, nil
	}
	return nil, error{fmt.Sprintf("%#v", c.value), v, path}
}

// OneOf returns a Checker that attempts to Coerce the value with each
// of the provided checkers. The value returned by the first checker
// that succeeds will be returned by the OneOf checker itself.  If no
// checker succeeds, OneOf will return an error on coercion.
func OneOf(options ...Checker) Checker {
	return oneOfC{options}
}

type oneOfC struct {
	options []Checker
}

func (c oneOfC) Coerce(v interface{}, path []string) (interface{}, os.Error) {
	for _, o := range c.options {
		newv, err := o.Coerce(v, path)
		if err == nil {
			return newv, nil
		}
	}
	return nil, error{path: path}
}

// Bool returns a Checker that accepts boolean values only.
func Bool() Checker {
	return boolC{}
}

type boolC struct{}

func (c boolC) Coerce(v interface{}, path []string) (interface{}, os.Error) {
	if v != nil && reflect.TypeOf(v).Kind() == reflect.Bool {
		return v, nil
	}
	return nil, error{"bool", v, path}
}

// Int returns a Checker that accepts any integer value, and returns
// the same value consistently typed as an int64.
func Int() Checker {
	return intC{}
}

type intC struct{}

func (c intC) Coerce(v interface{}, path []string) (interface{}, os.Error) {
	if v == nil {
		return nil, error{"int", v, path}
	}
	switch reflect.TypeOf(v).Kind() {
	case reflect.Int:
	case reflect.Int8:
	case reflect.Int16:
	case reflect.Int32:
	case reflect.Int64:
	default:
		return nil, error{"int", v, path}
	}
	return reflect.ValueOf(v).Int(), nil
}

// Int returns a Checker that accepts any float value, and returns
// the same value consistently typed as a float64.
func Float() Checker {
	return floatC{}
}

type floatC struct{}

func (c floatC) Coerce(v interface{}, path []string) (interface{}, os.Error) {
	if v == nil {
		return nil, error{"float", v, path}
	}
	switch reflect.TypeOf(v).Kind() {
	case reflect.Float32:
	case reflect.Float64:
	default:
		return nil, error{"float", v, path}
	}
	return reflect.ValueOf(v).Float(), nil
}


// String returns a Checker that accepts a string value only and returns
// it unprocessed.
func String() Checker {
	return stringC{}
}

type stringC struct{}

func (c stringC) Coerce(v interface{}, path []string) (interface{}, os.Error) {
	if v != nil && reflect.TypeOf(v).Kind() == reflect.String {
		return reflect.ValueOf(v).String(), nil
	}
	return nil, error{"string", v, path}
}

func SimpleRegexp() Checker {
	return sregexpC{}
}

type sregexpC struct{}

func (c sregexpC) Coerce(v interface{}, path []string) (interface{}, os.Error) {
	// XXX The regexp package happens to be extremely simple right now.
	//     Once exp/regexp goes mainstream, we'll have to update this
	//     logic to use a more widely accepted regexp subset.
	if v != nil && reflect.TypeOf(v).Kind() == reflect.String {
		s := reflect.ValueOf(v).String()
		_, err := regexp.Compile(s)
		if err != nil {
			return nil, error{"valid regexp", s, path}
		}
		return v, nil
	}
	return nil, error{"regexp string", v, path}
}

// List returns a Checker that accepts a slice value with values
// that are processed with the elem checker.  If any element of the
// provided slice value fails to be processed, processing will stop
// and return with the obtained error.
//
// The coerced output value has type schema.ListType.
func List(elem Checker) Checker {
	return listC{elem}
}

type listC struct {
	elem Checker
}

func (c listC) Coerce(v interface{}, path []string) (interface{}, os.Error) {
	rv := reflect.ValueOf(v)
	if rv.Kind() != reflect.Slice {
		return nil, error{"list", v, path}
	}

	path = append(path, "[", "?", "]")

	l := rv.Len()
	out := make(ListType, 0, l)
	for i := 0; i != l; i++ {
		path[len(path)-2] = strconv.Itoa(i)
		elem, err := c.elem.Coerce(rv.Index(i).Interface(), path)
		if err != nil {
			return nil, err
		}
		out = append(out, elem)
	}
	return out, nil
}

// Map returns a Checker that accepts a map value. Every key and value
// in the map are processed with the respective checker, and if any
// value fails to be coerced, processing stops and returns with the
// underlying error.
//
// The coerced output value has type schema.MapType.
func Map(key Checker, value Checker) Checker {
	return mapC{key, value}
}

type mapC struct {
	key Checker
	value Checker
}

func (c mapC) Coerce(v interface{}, path []string) (interface{}, os.Error) {
	rv := reflect.ValueOf(v)
	if rv.Kind() != reflect.Map {
		return nil, error{"map", v, path}
	}

	vpath := append(path, ".", "?")

	l := rv.Len()
	out := make(MapType, l)
	keys := rv.MapKeys()
	for i := 0; i != l; i++ {
		k := keys[i]
		newk, err := c.key.Coerce(k.Interface(), path)
		if err != nil {
			return nil, err
		}
		vpath[len(vpath)-1] = fmt.Sprint(k.Interface())
		newv, err := c.value.Coerce(rv.MapIndex(k).Interface(), vpath)
		if err != nil {
			return nil, err
		}
		out[newk] = newv
	}
	return out, nil
}

type Fields map[string]Checker
type Optional []string

// FieldMap returns a Checker that accepts a map value with defined
// string keys. Every key has an independent checker associated,
// and processing will only succeed if all the values succeed
// individually. If a field fails to be processed, processing stops
// and returns with the underlying error.
//
// The coerced output value has type schema.MapType.
func FieldMap(fields Fields, optional Optional) Checker {
	return fieldMapC{fields, optional}
}

type fieldMapC struct {
	fields Fields
	optional []string
}

func (c fieldMapC) isOptional(key string) bool {
	for _, k := range c.optional {
		if k == key {
			return true
		}
	}
	return false
}

func (c fieldMapC) Coerce(v interface{}, path []string) (interface{}, os.Error) {
	rv := reflect.ValueOf(v)
	if rv.Kind() != reflect.Map {
		return nil, error{"map", v, path}
	}

	vpath := append(path, ".", "?")

	l := rv.Len()
	out := make(MapType, l)
	for k, checker := range c.fields {
		vpath[len(vpath)-1] = k
		var value interface{}
		valuev := rv.MapIndex(reflect.ValueOf(k))
		if valuev.IsValid() {
			value = valuev.Interface()
		} else if c.isOptional(k) {
			continue
		}
		newv, err := checker.Coerce(value, vpath)
		if err != nil {
			return nil, err
		}
		out[k] = newv
	}
	return out, nil
}

// FieldMapSet returns a Checker that accepts a map value checked
// against one of several FieldMap checkers.  The actual checker
// used is the first one whose checker associated with the selector
// field processes the map correctly. If no checker processes
// the selector value correctly, an error is returned.
//
// The coerced output value has type schema.MapType.
func FieldMapSet(selector string, maps []Checker) Checker {
	fmaps := make([]fieldMapC, len(maps))
	for i, m := range maps {
		if fmap, ok := m.(fieldMapC); ok {
			if checker, _ := fmap.fields[selector]; checker == nil {
				panic("FieldMapSet has a FieldMap with a missing selector")
			}
			fmaps[i] = fmap
		} else {
			panic("FieldMapSet got a non-FieldMap checker")
		}
	}
	return mapSetC{selector, fmaps}
}

type mapSetC struct {
	selector string
	fmaps []fieldMapC
}

func (c mapSetC) Coerce(v interface{}, path []string) (interface{}, os.Error) {
	rv := reflect.ValueOf(v)
	if rv.Kind() != reflect.Map {
		return nil, error{"map", v, path}
	}

	var selector interface{}
	selectorv := rv.MapIndex(reflect.ValueOf(c.selector))
	if selectorv.IsValid() {
		selector = selectorv.Interface()
		for _, fmap := range c.fmaps {
			_, err := fmap.fields[c.selector].Coerce(selector, path)
			if err != nil {
				continue
			}
			return fmap.Coerce(v, path)
		}
	}
	return nil, error{"supported selector", selector, append(path, ".", c.selector)}
}