...

Source file src/github.com/pelletier/go-toml/tomltree_create.go

Documentation: github.com/pelletier/go-toml

     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  }
   156  

View as plain text