10 "github.com/mitchellh/mapstructure"
13 // MapFieldWriter writes data into a single map[string]string structure.
14 type MapFieldWriter struct {
15 Schema map[string]*Schema
18 result map[string]string
21 // Map returns the underlying map that is being written to.
22 func (w *MapFieldWriter) Map() map[string]string {
26 w.result = make(map[string]string)
32 func (w *MapFieldWriter) unsafeWriteField(addr string, value string) {
36 w.result = make(map[string]string)
39 w.result[addr] = value
42 func (w *MapFieldWriter) WriteField(addr []string, value interface{}) error {
46 w.result = make(map[string]string)
49 schemaList := addrToSchema(addr, w.Schema)
50 if len(schemaList) == 0 {
51 return fmt.Errorf("Invalid address to set: %#v", addr)
54 // If we're setting anything other than a list root or set root,
56 for _, schema := range schemaList[:len(schemaList)-1] {
57 if schema.Type == TypeList {
59 "%s: can only set full list",
60 strings.Join(addr, "."))
63 if schema.Type == TypeMap {
65 "%s: can only set full map",
66 strings.Join(addr, "."))
69 if schema.Type == TypeSet {
71 "%s: can only set full set",
72 strings.Join(addr, "."))
76 return w.set(addr, value)
79 func (w *MapFieldWriter) set(addr []string, value interface{}) error {
80 schemaList := addrToSchema(addr, w.Schema)
81 if len(schemaList) == 0 {
82 return fmt.Errorf("Invalid address to set: %#v", addr)
85 schema := schemaList[len(schemaList)-1]
87 case TypeBool, TypeInt, TypeFloat, TypeString:
88 return w.setPrimitive(addr, value, schema)
90 return w.setList(addr, value, schema)
92 return w.setMap(addr, value, schema)
94 return w.setSet(addr, value, schema)
96 return w.setObject(addr, value, schema)
98 panic(fmt.Sprintf("Unknown type: %#v", schema.Type))
102 func (w *MapFieldWriter) setList(
105 schema *Schema) error {
106 k := strings.Join(addr, ".")
107 setElement := func(idx string, value interface{}) error {
108 addrCopy := make([]string, len(addr), len(addr)+1)
110 return w.set(append(addrCopy, idx), value)
114 if err := mapstructure.Decode(v, &vs); err != nil {
115 return fmt.Errorf("%s: %s", k, err)
118 // Set the entire list.
120 for i, elem := range vs {
121 is := strconv.FormatInt(int64(i), 10)
122 err = setElement(is, elem)
128 for i, _ := range vs {
129 is := strconv.FormatInt(int64(i), 10)
136 w.result[k+".#"] = strconv.FormatInt(int64(len(vs)), 10)
140 func (w *MapFieldWriter) setMap(
143 schema *Schema) error {
144 k := strings.Join(addr, ".")
145 v := reflect.ValueOf(value)
146 vs := make(map[string]interface{})
149 // The empty string here means the map is removed.
154 if v.Kind() != reflect.Map {
155 return fmt.Errorf("%s: must be a map", k)
157 if v.Type().Key().Kind() != reflect.String {
158 return fmt.Errorf("%s: keys must strings", k)
160 for _, mk := range v.MapKeys() {
162 vs[mk.String()] = mv.Interface()
165 // Remove the pure key since we're setting the full map value
169 addrCopy := make([]string, len(addr), len(addr)+1)
171 for subKey, v := range vs {
172 if err := w.set(append(addrCopy, subKey), v); err != nil {
178 w.result[k+".%"] = strconv.Itoa(len(vs))
183 func (w *MapFieldWriter) setObject(
186 schema *Schema) error {
187 // Set the entire object. First decode into a proper structure
188 var v map[string]interface{}
189 if err := mapstructure.Decode(value, &v); err != nil {
190 return fmt.Errorf("%s: %s", strings.Join(addr, "."), err)
193 // Make space for additional elements in the address
194 addrCopy := make([]string, len(addr), len(addr)+1)
197 // Set each element in turn
199 for k1, v1 := range v {
200 if err = w.set(append(addrCopy, k1), v1); err != nil {
205 for k1, _ := range v {
206 w.set(append(addrCopy, k1), nil)
213 func (w *MapFieldWriter) setPrimitive(
216 schema *Schema) error {
217 k := strings.Join(addr, ".")
220 // The empty string here means the value is removed.
229 if err := mapstructure.Decode(v, &b); err != nil {
230 return fmt.Errorf("%s: %s", k, err)
233 set = strconv.FormatBool(b)
235 if err := mapstructure.Decode(v, &set); err != nil {
236 return fmt.Errorf("%s: %s", k, err)
240 if err := mapstructure.Decode(v, &n); err != nil {
241 return fmt.Errorf("%s: %s", k, err)
243 set = strconv.FormatInt(int64(n), 10)
246 if err := mapstructure.Decode(v, &n); err != nil {
247 return fmt.Errorf("%s: %s", k, err)
249 set = strconv.FormatFloat(float64(n), 'G', -1, 64)
251 return fmt.Errorf("Unknown type: %#v", schema.Type)
258 func (w *MapFieldWriter) setSet(
261 schema *Schema) error {
262 addrCopy := make([]string, len(addr), len(addr)+1)
264 k := strings.Join(addr, ".")
267 w.result[k+".#"] = "0"
271 // If it is a slice, then we have to turn it into a *Set so that
272 // we get the proper order back based on the hash code.
273 if v := reflect.ValueOf(value); v.Kind() == reflect.Slice {
274 // Build a temp *ResourceData to use for the conversion
275 tempSchema := *schema
276 tempSchema.Type = TypeList
277 tempSchemaMap := map[string]*Schema{addr[0]: &tempSchema}
278 tempW := &MapFieldWriter{Schema: tempSchemaMap}
280 // Set the entire list, this lets us get sane values out of it
281 if err := tempW.WriteField(addr, value); err != nil {
285 // Build the set by going over the list items in order and
286 // hashing them into the set. The reason we go over the list and
287 // not the `value` directly is because this forces all types
288 // to become []interface{} (generic) instead of []string, which
289 // most hash functions are expecting.
290 s := schema.ZeroValue().(*Set)
291 tempR := &MapFieldReader{
292 Map: BasicMapReader(tempW.Map()),
293 Schema: tempSchemaMap,
295 for i := 0; i < v.Len(); i++ {
296 is := strconv.FormatInt(int64(i), 10)
297 result, err := tempR.ReadField(append(addrCopy, is))
302 panic("set item just set doesn't exist")
311 for code, elem := range value.(*Set).m {
312 if err := w.set(append(addrCopy, code), elem); err != nil {
317 w.result[k+".#"] = strconv.Itoa(value.(*Set).Len())