267 lines
5.6 KiB
Go
267 lines
5.6 KiB
Go
|
package internal
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"reflect"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
// Fill the fields of the element.
|
||
|
// nodes -> element
|
||
|
func Fill(element interface{}, node *Node) error {
|
||
|
if element == nil || node == nil {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
if node.Kind == 0 {
|
||
|
return fmt.Errorf("missing node type: %s", node.Name)
|
||
|
}
|
||
|
|
||
|
elem := reflect.ValueOf(element)
|
||
|
if elem.Kind() == reflect.Struct {
|
||
|
return fmt.Errorf("struct are not supported, use pointer instead")
|
||
|
}
|
||
|
|
||
|
return fill(elem.Elem(), node)
|
||
|
}
|
||
|
|
||
|
func fill(field reflect.Value, node *Node) error {
|
||
|
// related to allow-empty tag
|
||
|
if node.Disabled {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
switch field.Kind() {
|
||
|
case reflect.String:
|
||
|
field.SetString(node.Value)
|
||
|
return nil
|
||
|
case reflect.Bool:
|
||
|
val, err := strconv.ParseBool(node.Value)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
field.SetBool(val)
|
||
|
return nil
|
||
|
case reflect.Int8:
|
||
|
return setInt(field, node.Value, 8)
|
||
|
case reflect.Int16:
|
||
|
return setInt(field, node.Value, 16)
|
||
|
case reflect.Int32:
|
||
|
return setInt(field, node.Value, 32)
|
||
|
case reflect.Int64, reflect.Int:
|
||
|
return setInt(field, node.Value, 64)
|
||
|
case reflect.Uint8:
|
||
|
return setUint(field, node.Value, 8)
|
||
|
case reflect.Uint16:
|
||
|
return setUint(field, node.Value, 16)
|
||
|
case reflect.Uint32:
|
||
|
return setUint(field, node.Value, 32)
|
||
|
case reflect.Uint64, reflect.Uint:
|
||
|
return setUint(field, node.Value, 64)
|
||
|
case reflect.Float32:
|
||
|
return setFloat(field, node.Value, 32)
|
||
|
case reflect.Float64:
|
||
|
return setFloat(field, node.Value, 64)
|
||
|
case reflect.Struct:
|
||
|
return setStruct(field, node)
|
||
|
case reflect.Ptr:
|
||
|
return setPtr(field, node)
|
||
|
case reflect.Map:
|
||
|
return setMap(field, node)
|
||
|
case reflect.Slice:
|
||
|
return setSlice(field, node)
|
||
|
default:
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func setPtr(field reflect.Value, node *Node) error {
|
||
|
if field.IsNil() {
|
||
|
field.Set(reflect.New(field.Type().Elem()))
|
||
|
}
|
||
|
|
||
|
return fill(field.Elem(), node)
|
||
|
}
|
||
|
|
||
|
func setStruct(field reflect.Value, node *Node) error {
|
||
|
for _, child := range node.Children {
|
||
|
fd := field.FieldByName(child.FieldName)
|
||
|
|
||
|
zeroValue := reflect.Value{}
|
||
|
if fd == zeroValue {
|
||
|
return fmt.Errorf("field not found, node: %s (%s)", child.Name, child.FieldName)
|
||
|
}
|
||
|
|
||
|
err := fill(fd, child)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func setSlice(field reflect.Value, node *Node) error {
|
||
|
if field.Type().Elem().Kind() == reflect.Struct {
|
||
|
return setSliceAsStruct(field, node)
|
||
|
}
|
||
|
|
||
|
if len(node.Value) == 0 {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
values := strings.Split(node.Value, ",")
|
||
|
|
||
|
slice := reflect.MakeSlice(field.Type(), len(values), len(values))
|
||
|
field.Set(slice)
|
||
|
|
||
|
for i := 0; i < len(values); i++ {
|
||
|
value := strings.TrimSpace(values[i])
|
||
|
|
||
|
switch field.Type().Elem().Kind() {
|
||
|
case reflect.String:
|
||
|
field.Index(i).Set(reflect.ValueOf(value))
|
||
|
case reflect.Int:
|
||
|
val, err := strconv.ParseInt(value, 10, 64)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
field.Index(i).SetInt(val)
|
||
|
case reflect.Int8:
|
||
|
err := setInt(field.Index(i), value, 8)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
case reflect.Int16:
|
||
|
err := setInt(field.Index(i), value, 16)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
case reflect.Int32:
|
||
|
err := setInt(field.Index(i), value, 32)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
case reflect.Int64:
|
||
|
err := setInt(field.Index(i), value, 64)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
case reflect.Uint:
|
||
|
val, err := strconv.ParseUint(value, 10, 64)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
field.Index(i).SetUint(val)
|
||
|
case reflect.Uint8:
|
||
|
err := setUint(field.Index(i), value, 8)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
case reflect.Uint16:
|
||
|
err := setUint(field.Index(i), value, 16)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
case reflect.Uint32:
|
||
|
err := setUint(field.Index(i), value, 32)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
case reflect.Uint64:
|
||
|
err := setUint(field.Index(i), value, 64)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
case reflect.Float32:
|
||
|
err := setFloat(field.Index(i), value, 32)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
case reflect.Float64:
|
||
|
err := setFloat(field.Index(i), value, 64)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
case reflect.Bool:
|
||
|
val, err := strconv.ParseBool(value)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
field.Index(i).SetBool(val)
|
||
|
default:
|
||
|
return fmt.Errorf("unsupported type: %s", field.Type().Elem())
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func setSliceAsStruct(field reflect.Value, node *Node) error {
|
||
|
if len(node.Children) == 0 {
|
||
|
return fmt.Errorf("invalid slice: node %s", node.Name)
|
||
|
}
|
||
|
|
||
|
elem := reflect.New(field.Type().Elem()).Elem()
|
||
|
err := setStruct(elem, node)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
field.Set(reflect.MakeSlice(field.Type(), 1, 1))
|
||
|
field.Index(0).Set(elem)
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func setMap(field reflect.Value, node *Node) error {
|
||
|
if field.IsNil() {
|
||
|
field.Set(reflect.MakeMap(field.Type()))
|
||
|
}
|
||
|
|
||
|
for _, child := range node.Children {
|
||
|
ptrValue := reflect.New(reflect.PtrTo(field.Type().Elem()))
|
||
|
|
||
|
err := fill(ptrValue, child)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
value := ptrValue.Elem().Elem()
|
||
|
|
||
|
key := reflect.ValueOf(child.Name)
|
||
|
field.SetMapIndex(key, value)
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func setInt(field reflect.Value, value string, bitSize int) error {
|
||
|
val, err := strconv.ParseInt(value, 10, bitSize)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
field.Set(reflect.ValueOf(val).Convert(field.Type()))
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func setUint(field reflect.Value, value string, bitSize int) error {
|
||
|
val, err := strconv.ParseUint(value, 10, bitSize)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
field.Set(reflect.ValueOf(val).Convert(field.Type()))
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func setFloat(field reflect.Value, value string, bitSize int) error {
|
||
|
val, err := strconv.ParseFloat(value, bitSize)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
field.Set(reflect.ValueOf(val).Convert(field.Type()))
|
||
|
return nil
|
||
|
}
|