blob: ec88e562ecbf18b6d4572c03bdb05368e5720e56 [file] [log] [blame]
David K. Bainbridge528b3182017-01-23 08:51:59 -08001// Copyright 2015 Canonical Ltd.
2// Licensed under the LGPLv3, see LICENCE file for details.
3
4package schema
5
6import (
7 "reflect"
8 "strconv"
9)
10
11// Bool returns a Checker that accepts boolean values only.
12func Bool() Checker {
13 return boolC{}
14}
15
16type boolC struct{}
17
18func (c boolC) Coerce(v interface{}, path []string) (interface{}, error) {
19 if v != nil {
20 switch reflect.TypeOf(v).Kind() {
21 case reflect.Bool:
22 return v, nil
23 case reflect.String:
24 val, err := strconv.ParseBool(reflect.ValueOf(v).String())
25 if err == nil {
26 return val, nil
27 }
28 }
29 }
30 return nil, error_{"bool", v, path}
31}
32
33// Int returns a Checker that accepts any integer value, and returns
34// the same value consistently typed as an int64.
35func Int() Checker {
36 return intC{}
37}
38
39type intC struct{}
40
41func (c intC) Coerce(v interface{}, path []string) (interface{}, error) {
42 if v == nil {
43 return nil, error_{"int", v, path}
44 }
45 switch reflect.TypeOf(v).Kind() {
46 case reflect.Int:
47 case reflect.Int8:
48 case reflect.Int16:
49 case reflect.Int32:
50 case reflect.Int64:
51 case reflect.String:
52 val, err := strconv.ParseInt(reflect.ValueOf(v).String(), 0, 64)
53 if err == nil {
54 return val, nil
55 } else {
56 return nil, error_{"int", v, path}
57 }
58 default:
59 return nil, error_{"int", v, path}
60 }
61 return reflect.ValueOf(v).Int(), nil
62}
63
64// Uint returns a Checker that accepts any integer or unsigned value, and
65// returns the same value consistently typed as an uint64. If the integer
66// value is negative an error is raised.
67func Uint() Checker {
68 return uintC{}
69}
70
71type uintC struct{}
72
73func (c uintC) Coerce(v interface{}, path []string) (interface{}, error) {
74 if v == nil {
75 return nil, error_{"uint", v, path}
76 }
77 switch reflect.TypeOf(v).Kind() {
78 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
79 return reflect.ValueOf(v).Uint(), nil
80 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
81 val := reflect.ValueOf(v).Int()
82 if val < 0 {
83 return nil, error_{"uint", v, path}
84 }
85 // All positive int64 values fit into uint64.
86 return uint64(val), nil
87 case reflect.String:
88 val, err := strconv.ParseUint(reflect.ValueOf(v).String(), 0, 64)
89 if err == nil {
90 return val, nil
91 } else {
92 return nil, error_{"uint", v, path}
93 }
94 default:
95 return nil, error_{"uint", v, path}
96 }
97}
98
99// ForceInt returns a Checker that accepts any integer or float value, and
100// returns the same value consistently typed as an int. This is required
101// in order to handle the interface{}/float64 type conversion performed by
102// the JSON serializer used as part of the API infrastructure.
103func ForceInt() Checker {
104 return forceIntC{}
105}
106
107type forceIntC struct{}
108
109func (c forceIntC) Coerce(v interface{}, path []string) (interface{}, error) {
110 if v != nil {
111 switch vv := reflect.TypeOf(v); vv.Kind() {
112 case reflect.String:
113 vstr := reflect.ValueOf(v).String()
114 intValue, err := strconv.ParseInt(vstr, 0, 64)
115 if err == nil {
116 return int(intValue), nil
117 }
118 floatValue, err := strconv.ParseFloat(vstr, 64)
119 if err == nil {
120 return int(floatValue), nil
121 }
122 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
123 return int(reflect.ValueOf(v).Int()), nil
124 case reflect.Float32, reflect.Float64:
125 return int(reflect.ValueOf(v).Float()), nil
126 }
127 }
128 return nil, error_{"number", v, path}
129}
130
131// ForceUint returns a Checker that accepts any integer or float value, and
132// returns the same value consistently typed as an uint64. This is required
133// in order to handle the interface{}/float64 type conversion performed by
134// the JSON serializer used as part of the API infrastructure. If the integer
135// value is negative an error is raised.
136func ForceUint() Checker {
137 return forceUintC{}
138}
139
140type forceUintC struct{}
141
142func (c forceUintC) Coerce(v interface{}, path []string) (interface{}, error) {
143 if v != nil {
144 switch vv := reflect.TypeOf(v); vv.Kind() {
145 case reflect.String:
146 vstr := reflect.ValueOf(v).String()
147 intValue, err := strconv.ParseUint(vstr, 0, 64)
148 if err == nil {
149 return intValue, nil
150 }
151 floatValue, err := strconv.ParseFloat(vstr, 64)
152 if err == nil {
153 if floatValue < 0 {
154 return nil, error_{"uint", v, path}
155 }
156 return uint64(floatValue), nil
157 }
158 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
159 return reflect.ValueOf(v).Uint(), nil
160 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
161 val := reflect.ValueOf(v).Int()
162 if val < 0 {
163 return nil, error_{"uint", v, path}
164 }
165 // All positive int64 values fit into uint64.
166 return uint64(val), nil
167 case reflect.Float32, reflect.Float64:
168 val := reflect.ValueOf(v).Float()
169 if val < 0 {
170 return nil, error_{"uint", v, path}
171 }
172 return uint64(val), nil
173 }
174 }
175 return nil, error_{"uint", v, path}
176}
177
178// Float returns a Checker that accepts any float value, and returns
179// the same value consistently typed as a float64.
180func Float() Checker {
181 return floatC{}
182}
183
184type floatC struct{}
185
186func (c floatC) Coerce(v interface{}, path []string) (interface{}, error) {
187 if v == nil {
188 return nil, error_{"float", v, path}
189 }
190 switch reflect.TypeOf(v).Kind() {
191 case reflect.Float32:
192 case reflect.Float64:
193 default:
194 return nil, error_{"float", v, path}
195 }
196 return reflect.ValueOf(v).Float(), nil
197}