/* Given a thing (field value in a struct), set the thing with the element in the map (key) the map value to the proper type. */ func set_value(thing reflect.Value, kind reflect.Kind, key string, tag_id string, pfx string, annon bool, m map[string]string) { if !thing.CanAddr() { // prevent stack dump return } switch kind { default: fmt.Fprintf(os.Stderr, "transform.mts: tagged sturct member cannot be converted from map: tag=%s kind=%v\n", key, thing.Kind()) case reflect.String: thing.SetString(m[key]) case reflect.Ptr: p := thing.Elem() // get the pointer value; allows us to suss the type if !p.IsValid() { // ptr is nill in the struct so we must allocate a pointer to 0 so it can be changed below thing.Set(reflect.New(thing.Type().Elem())) p = thing.Elem() } switch p.Kind() { case reflect.String: s := m[key] // copy it and then point to the copy thing.Set(reflect.ValueOf(&s)) case reflect.Int: i := clike.Atoi(m[key]) // convert to integer and then point at the value thing.Set(reflect.ValueOf(&i)) case reflect.Int64: i := clike.Atoi64(m[key]) thing.Set(reflect.ValueOf(&i)) case reflect.Int32: i := clike.Atoi32(m[key]) thing.Set(reflect.ValueOf(&i)) case reflect.Int16: i := clike.Atoi16(m[key]) thing.Set(reflect.ValueOf(&i)) case reflect.Int8: i := int8(clike.Atoi16(m[key])) thing.Set(reflect.ValueOf(&i)) case reflect.Uint: ui := clike.Atou(m[key]) thing.Set(reflect.ValueOf(&ui)) case reflect.Uint64: ui := clike.Atou64(m[key]) thing.Set(reflect.ValueOf(&ui)) case reflect.Uint32: ui := clike.Atou32(m[key]) thing.Set(reflect.ValueOf(&ui)) case reflect.Uint16: ui := clike.Atou16(m[key]) thing.Set(reflect.ValueOf(&ui)) case reflect.Uint8: ui := uint8(clike.Atou16(m[key])) thing.Set(reflect.ValueOf(&ui)) case reflect.Float64: fv := clike.Atof(m[key]) thing.Set(reflect.ValueOf(&fv)) case reflect.Float32: fv := float32(clike.Atof(m[key])) thing.Set(reflect.ValueOf(&fv)) case reflect.Bool: b := m[key] == "true" || m[key] == "True" || m[key] == "TRUE" thing.Set(reflect.ValueOf(&b)) case reflect.Struct: map_to_struct(m, p, p.Type(), tag_id, pfx) // recurse to process } case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8: thing.SetInt(clike.Atoi64(m[key])) case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8: thing.SetUint(uint64(clike.Atoi64(m[key]))) case reflect.Float64, reflect.Float32: thing.SetFloat(clike.Atof(m[key])) case reflect.Bool: thing.SetBool(m[key] == "true") case reflect.Map: new_map := reflect.MakeMap(thing.Type()) // create the map thing.Set(new_map) // put it in the struct idx := key + "/" // now populate the map ilen := len(idx) for k, _ := range m { // we could keep a separate list of keys, but for now this should do if strings.HasPrefix(k, key) { tokens := strings.Split(k[ilen:], "/") map_key := reflect.ValueOf(tokens[0]) // map key is everything past the tag to the next slant map_ele_type := new_map.Type().Elem() // the type of the element that the map references mthing := reflect.New(map_ele_type).Elem() // new returns pointer, so dereference with Elem() (value not type!) set_value(mthing, mthing.Kind(), idx+tokens[0], tag_id, idx+tokens[0]+"/", false, m) // put the value into the map thing new_map.SetMapIndex(map_key, mthing) // put it into the map (order IS important; add to map after recursion) //fmt.Fprintf( os.Stderr, "saving: %s thing-type=%s mthing=%s\n", map_key, thing.Type(), mthing ) } } case reflect.Slice: c := clike.Atoi(m[key+".cap"]) l := clike.Atoi(m[key+".len"]) thing.Set(reflect.MakeSlice(thing.Type(), l, c)) // create a new slice with the same len/cap that it had for j := 0; j < l; j++ { idx := fmt.Sprintf("%s/%d", key, j) set_value(thing.Index(j), thing.Type().Elem().Kind(), idx, tag_id, idx+"/", false, m) // populate each value of the slice up to len } case reflect.Struct: if annon { map_to_struct(m, thing, thing.Type(), tag_id, key) // anon structs share namespace, so prefix is the same } else { map_to_struct(m, thing, thing.Type(), tag_id, pfx) // dive to get the substruct adding a level to the prefix } } }
/* Internal funciton to convert an interface into a supported desired value. */ func cvt2desired(v interface{}, desired int) interface{} { switch v.(type) { case string: switch desired { case ET_STRING: return v case ET_STRINGP: return &v case ET_INT: return v.(int) case ET_UINT: return v.(uint) case ET_INT64: return v.(int64) case ET_FLOAT: return v.(float64) case ET_BOOL: return v == "true" } case *string: switch desired { case ET_STRING: return *(v.(*string)) case ET_STRINGP: return v case ET_INT: return clike.Atoi(*(v.(*string))) case ET_UINT: return clike.Atou(*(v.(*string))) case ET_INT64: return clike.Atoll(*(v.(*string))) case ET_FLOAT: return clike.Atof(*(v.(*string))) case ET_BOOL: return *(v.(*string)) == "true" } case float64: switch desired { case ET_STRING: return fmt.Sprintf("%.2f", v) case ET_STRINGP: s := fmt.Sprintf("%.2f", v) return &s case ET_INT: return int(v.(float64)) case ET_UINT: return uint(v.(float64)) case ET_INT64: return int64(v.(float64)) case ET_FLOAT: return v case ET_BOOL: return v.(float64) != 0.0 } case int: switch desired { case ET_STRING: return fmt.Sprintf("%d", v) case ET_STRINGP: s := fmt.Sprintf("%d", v) return &s case ET_INT: return v case ET_UINT: return uint(v.(int)) case ET_INT64: return int64(v.(int)) case ET_FLOAT: return float64(v.(int)) case ET_BOOL: return v.(int) != 0 } case int64: switch desired { case ET_STRING: return fmt.Sprintf("%d", v) case ET_STRINGP: s := fmt.Sprintf("%d", v) return &s case ET_INT: return int(v.(int64)) case ET_UINT: return uint(v.(int64)) case ET_INT64: return v case ET_FLOAT: return float64(v.(int64)) case ET_BOOL: return v.(int64) != 0 } case bool: switch desired { case ET_STRING: return fmt.Sprintf("%v", v) case ET_STRINGP: s := fmt.Sprintf("%v", v) return &s case ET_INT: if v.(bool) { return int(1) } else { return int(0) } case ET_UINT: if v.(bool) { return uint(1) } else { return uint(0) } case ET_INT64: if v.(bool) { return int64(1) } else { return int64(0) } case ET_FLOAT: if v.(bool) { return 1.0 } else { return 0.0 } case ET_BOOL: return v } } return nil }