vendor/github.com/pelletier/go-toml/tomltree_create.go
changeset 265 05c40b36d3b2
parent 264 8f478162d991
child 266 80973a656b81
equal deleted inserted replaced
264:8f478162d991 265:05c40b36d3b2
     1 package toml
       
     2 
       
     3 import (
       
     4 	"fmt"
       
     5 	"reflect"
       
     6 	"time"
       
     7 )
       
     8 
       
     9 var kindToType = [reflect.String + 1]reflect.Type{
       
    10 	reflect.Bool:    reflect.TypeOf(true),
       
    11 	reflect.String:  reflect.TypeOf(""),
       
    12 	reflect.Float32: reflect.TypeOf(float64(1)),
       
    13 	reflect.Float64: reflect.TypeOf(float64(1)),
       
    14 	reflect.Int:     reflect.TypeOf(int64(1)),
       
    15 	reflect.Int8:    reflect.TypeOf(int64(1)),
       
    16 	reflect.Int16:   reflect.TypeOf(int64(1)),
       
    17 	reflect.Int32:   reflect.TypeOf(int64(1)),
       
    18 	reflect.Int64:   reflect.TypeOf(int64(1)),
       
    19 	reflect.Uint:    reflect.TypeOf(uint64(1)),
       
    20 	reflect.Uint8:   reflect.TypeOf(uint64(1)),
       
    21 	reflect.Uint16:  reflect.TypeOf(uint64(1)),
       
    22 	reflect.Uint32:  reflect.TypeOf(uint64(1)),
       
    23 	reflect.Uint64:  reflect.TypeOf(uint64(1)),
       
    24 }
       
    25 
       
    26 // typeFor returns a reflect.Type for a reflect.Kind, or nil if none is found.
       
    27 // supported values:
       
    28 // string, bool, int64, uint64, float64, time.Time, int, int8, int16, int32, uint, uint8, uint16, uint32, float32
       
    29 func typeFor(k reflect.Kind) reflect.Type {
       
    30 	if k > 0 && int(k) < len(kindToType) {
       
    31 		return kindToType[k]
       
    32 	}
       
    33 	return nil
       
    34 }
       
    35 
       
    36 func simpleValueCoercion(object interface{}) (interface{}, error) {
       
    37 	switch original := object.(type) {
       
    38 	case string, bool, int64, uint64, float64, time.Time:
       
    39 		return original, nil
       
    40 	case int:
       
    41 		return int64(original), nil
       
    42 	case int8:
       
    43 		return int64(original), nil
       
    44 	case int16:
       
    45 		return int64(original), nil
       
    46 	case int32:
       
    47 		return int64(original), nil
       
    48 	case uint:
       
    49 		return uint64(original), nil
       
    50 	case uint8:
       
    51 		return uint64(original), nil
       
    52 	case uint16:
       
    53 		return uint64(original), nil
       
    54 	case uint32:
       
    55 		return uint64(original), nil
       
    56 	case float32:
       
    57 		return float64(original), nil
       
    58 	case fmt.Stringer:
       
    59 		return original.String(), nil
       
    60 	case []interface{}:
       
    61 		value := reflect.ValueOf(original)
       
    62 		length := value.Len()
       
    63 		arrayValue := reflect.MakeSlice(value.Type(), 0, length)
       
    64 		for i := 0; i < length; i++ {
       
    65 			val := value.Index(i).Interface()
       
    66 			simpleValue, err := simpleValueCoercion(val)
       
    67 			if err != nil {
       
    68 				return nil, err
       
    69 			}
       
    70 			arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue))
       
    71 		}
       
    72 		return arrayValue.Interface(), nil
       
    73 	default:
       
    74 		return nil, fmt.Errorf("cannot convert type %T to Tree", object)
       
    75 	}
       
    76 }
       
    77 
       
    78 func sliceToTree(object interface{}) (interface{}, error) {
       
    79 	// arrays are a bit tricky, since they can represent either a
       
    80 	// collection of simple values, which is represented by one
       
    81 	// *tomlValue, or an array of tables, which is represented by an
       
    82 	// array of *Tree.
       
    83 
       
    84 	// holding the assumption that this function is called from toTree only when value.Kind() is Array or Slice
       
    85 	value := reflect.ValueOf(object)
       
    86 	insideType := value.Type().Elem()
       
    87 	length := value.Len()
       
    88 	if length > 0 {
       
    89 		insideType = reflect.ValueOf(value.Index(0).Interface()).Type()
       
    90 	}
       
    91 	if insideType.Kind() == reflect.Map {
       
    92 		// this is considered as an array of tables
       
    93 		tablesArray := make([]*Tree, 0, length)
       
    94 		for i := 0; i < length; i++ {
       
    95 			table := value.Index(i)
       
    96 			tree, err := toTree(table.Interface())
       
    97 			if err != nil {
       
    98 				return nil, err
       
    99 			}
       
   100 			tablesArray = append(tablesArray, tree.(*Tree))
       
   101 		}
       
   102 		return tablesArray, nil
       
   103 	}
       
   104 
       
   105 	sliceType := typeFor(insideType.Kind())
       
   106 	if sliceType == nil {
       
   107 		sliceType = insideType
       
   108 	}
       
   109 
       
   110 	arrayValue := reflect.MakeSlice(reflect.SliceOf(sliceType), 0, length)
       
   111 
       
   112 	for i := 0; i < length; i++ {
       
   113 		val := value.Index(i).Interface()
       
   114 		simpleValue, err := simpleValueCoercion(val)
       
   115 		if err != nil {
       
   116 			return nil, err
       
   117 		}
       
   118 		arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue))
       
   119 	}
       
   120 	return &tomlValue{value: arrayValue.Interface(), position: Position{}}, nil
       
   121 }
       
   122 
       
   123 func toTree(object interface{}) (interface{}, error) {
       
   124 	value := reflect.ValueOf(object)
       
   125 
       
   126 	if value.Kind() == reflect.Map {
       
   127 		values := map[string]interface{}{}
       
   128 		keys := value.MapKeys()
       
   129 		for _, key := range keys {
       
   130 			if key.Kind() != reflect.String {
       
   131 				if _, ok := key.Interface().(string); !ok {
       
   132 					return nil, fmt.Errorf("map key needs to be a string, not %T (%v)", key.Interface(), key.Kind())
       
   133 				}
       
   134 			}
       
   135 
       
   136 			v := value.MapIndex(key)
       
   137 			newValue, err := toTree(v.Interface())
       
   138 			if err != nil {
       
   139 				return nil, err
       
   140 			}
       
   141 			values[key.String()] = newValue
       
   142 		}
       
   143 		return &Tree{values: values, position: Position{}}, nil
       
   144 	}
       
   145 
       
   146 	if value.Kind() == reflect.Array || value.Kind() == reflect.Slice {
       
   147 		return sliceToTree(object)
       
   148 	}
       
   149 
       
   150 	simpleValue, err := simpleValueCoercion(object)
       
   151 	if err != nil {
       
   152 		return nil, err
       
   153 	}
       
   154 	return &tomlValue{value: simpleValue, position: Position{}}, nil
       
   155 }