github.com/profzone/eden-framework@v1.0.10/pkg/strings/stringifier.go (about)

     1  package str
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"reflect"
     7  	"strconv"
     8  	"strings"
     9  )
    10  
    11  var (
    12  	UnSupportTypeError = errors.New("un support type")
    13  )
    14  
    15  type StringUnmarshal func(s string, v reflect.Value) (bool, error)
    16  
    17  type Stringifier struct {
    18  	stringUnmarshalList []StringUnmarshal
    19  }
    20  
    21  func (stringifier *Stringifier) Register(stringUnmarshalList ...StringUnmarshal) {
    22  	stringifier.stringUnmarshalList = append(stringifier.stringUnmarshalList, stringUnmarshalList...)
    23  }
    24  
    25  func (stringifier Stringifier) Unmarshal(str string, rv reflect.Value) error {
    26  	rv = reflect.Indirect(rv)
    27  	for _, stringUnmarshal := range stringifier.stringUnmarshalList {
    28  		matched, err := stringUnmarshal(str, rv)
    29  		if matched {
    30  			if err != nil {
    31  				return fmt.Errorf("unmarshal failed for %v: %s", stringUnmarshal, err.Error())
    32  			}
    33  			return nil
    34  		}
    35  	}
    36  	return stringifier.UnmarshalBuiltIn(str, rv)
    37  }
    38  
    39  func (stringifier Stringifier) UnmarshalBuiltIn(str string, rv reflect.Value) error {
    40  	switch rv.Kind() {
    41  	case reflect.String:
    42  		rv.SetString(str)
    43  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    44  		intV, err := strconv.ParseInt(str, 10, getBitSize(rv))
    45  		if err != nil {
    46  			return err
    47  		}
    48  		rv.Set(reflect.ValueOf(intV).Convert(rv.Type()))
    49  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
    50  		uintV, err := strconv.ParseUint(str, 10, getBitSize(rv))
    51  		if err != nil {
    52  			return err
    53  		}
    54  		rv.Set(reflect.ValueOf(uintV).Convert(rv.Type()))
    55  	case reflect.Float32, reflect.Float64:
    56  		bitSize := getBitSize(rv)
    57  		floatV, err := strconv.ParseFloat(str, bitSize)
    58  		if err != nil {
    59  			return err
    60  		}
    61  		rv.Set(reflect.ValueOf(floatV).Convert(rv.Type()))
    62  	case reflect.Bool:
    63  		boolV, err := strconv.ParseBool(str)
    64  		if err != nil {
    65  			return err
    66  		}
    67  		rv.SetBool(boolV)
    68  	case reflect.Slice, reflect.Array:
    69  		if str != "" {
    70  			subStrValues := strings.Split(str, ",")
    71  			elemType := rv.Type().Elem()
    72  			tmpSlice := reflect.MakeSlice(reflect.SliceOf(elemType), 0, 0)
    73  			for _, subStrValue := range subStrValues {
    74  				elemValue := reflect.New(elemType)
    75  				err := stringifier.Unmarshal(subStrValue, elemValue)
    76  				if err != nil {
    77  					return err
    78  				}
    79  				tmpSlice = reflect.Append(tmpSlice, elemValue.Elem())
    80  			}
    81  			rv.Set(tmpSlice)
    82  		}
    83  	default:
    84  		return UnSupportTypeError
    85  	}
    86  	return nil
    87  }
    88  
    89  func getBitSize(v reflect.Value) int {
    90  	switch v.Kind() {
    91  	case reflect.Int, reflect.Uint:
    92  		return 32
    93  	case reflect.Int8, reflect.Uint8:
    94  		return 8
    95  	case reflect.Int16, reflect.Uint16:
    96  		return 16
    97  	case reflect.Int32, reflect.Uint32, reflect.Float32:
    98  		return 32
    99  	case reflect.Int64, reflect.Uint64, reflect.Float64:
   100  		return 64
   101  	default:
   102  		panic("only int, uint and float can support getBitSize")
   103  	}
   104  }