github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/x/textx/text.go (about)

     1  package textx
     2  
     3  import (
     4  	"bytes"
     5  	"encoding"
     6  	"encoding/base64"
     7  	"reflect"
     8  	"strconv"
     9  
    10  	"github.com/pkg/errors"
    11  )
    12  
    13  func MarshalText(v interface{}, useBase64 ...bool) ([]byte, error) {
    14  	if rv, ok := v.(reflect.Value); ok {
    15  		for rv.Kind() == reflect.Ptr {
    16  			if rv.IsNil() {
    17  				return nil, nil
    18  			}
    19  			rv = rv.Elem()
    20  		}
    21  
    22  		if rv.CanInterface() {
    23  			v = rv.Interface()
    24  		}
    25  	}
    26  
    27  	if marshaler, ok := v.(encoding.TextMarshaler); ok {
    28  		return marshaler.MarshalText()
    29  	}
    30  
    31  	if v == nil {
    32  		return nil, nil
    33  	}
    34  
    35  	switch x := v.(type) {
    36  	case []byte:
    37  		if len(useBase64) > 0 && useBase64[0] {
    38  			return ToBase64(x), nil
    39  		}
    40  		return x, nil
    41  	case string:
    42  		return []byte(x), nil
    43  	case bool:
    44  		return strconv.AppendBool([]byte{}, x), nil
    45  	case int:
    46  		return strconv.AppendInt([]byte{}, int64(x), 10), nil
    47  	case int8:
    48  		return strconv.AppendInt([]byte{}, int64(x), 10), nil
    49  	case int16:
    50  		return strconv.AppendInt([]byte{}, int64(x), 10), nil
    51  	case int32:
    52  		return strconv.AppendInt([]byte{}, int64(x), 10), nil
    53  	case int64:
    54  		return strconv.AppendInt([]byte{}, x, 10), nil
    55  	case uint:
    56  		return strconv.AppendUint([]byte{}, uint64(x), 10), nil
    57  	case uint8:
    58  		return strconv.AppendUint([]byte{}, uint64(x), 10), nil
    59  	case uint16:
    60  		return strconv.AppendUint([]byte{}, uint64(x), 10), nil
    61  	case uint32:
    62  		return strconv.AppendUint([]byte{}, uint64(x), 10), nil
    63  	case uint64:
    64  		return strconv.AppendUint([]byte{}, x, 10), nil
    65  	case float32:
    66  		return strconv.AppendFloat([]byte{}, float64(x), 'g', -1, 32), nil
    67  	case float64:
    68  		return strconv.AppendFloat([]byte{}, x, 'g', -1, 64), nil
    69  	default:
    70  		rv := reflect.ValueOf(x)
    71  
    72  		for rv.Kind() == reflect.Ptr {
    73  			if rv.IsNil() {
    74  				return nil, nil
    75  			}
    76  			rv = rv.Elem()
    77  		}
    78  
    79  		switch rv.Kind() {
    80  		case reflect.Slice:
    81  			elem := rv.Type().Elem()
    82  			if elem.Kind() == reflect.Uint8 && elem.PkgPath() == "" {
    83  				if len(useBase64) > 0 && useBase64[0] {
    84  					return ToBase64(rv.Bytes()), nil
    85  				}
    86  				return rv.Bytes(), nil
    87  			}
    88  		case reflect.String:
    89  			return []byte(rv.String()), nil
    90  		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    91  			return strconv.AppendInt([]byte{}, rv.Int(), 10), nil
    92  		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
    93  			return strconv.AppendUint([]byte{}, rv.Uint(), 10), nil
    94  		case reflect.Float32:
    95  			return strconv.AppendFloat([]byte{}, rv.Float(), 'g', -1, 32), nil
    96  		case reflect.Float64:
    97  			return strconv.AppendFloat([]byte{}, rv.Float(), 'g', -1, 64), nil
    98  		case reflect.Bool:
    99  			return strconv.AppendBool([]byte{}, rv.Bool()), nil
   100  		}
   101  		return nil, errors.Errorf("unsupported type %T", x)
   102  	}
   103  }
   104  
   105  func UnmarshalText(v interface{}, data []byte, useBase64 ...bool) error {
   106  	if rv, ok := v.(reflect.Value); ok {
   107  		if rv.Kind() != reflect.Ptr {
   108  			rv = rv.Addr()
   109  		} else {
   110  			if rv.IsNil() {
   111  				rv.Set(NewReflectValue(rv.Type()))
   112  			}
   113  		}
   114  
   115  		if rv.CanInterface() {
   116  			if unmarshaler, ok := rv.Interface().(encoding.TextUnmarshaler); ok {
   117  				if err := unmarshaler.UnmarshalText(data); err != nil {
   118  					return errors.Wrapf(err, "unmarshal text to %T failed", v)
   119  				}
   120  				return nil
   121  			}
   122  		}
   123  
   124  		return UnmarshalTextToReflectValue(rv, data)
   125  	}
   126  
   127  	if unmarshaler, ok := v.(encoding.TextUnmarshaler); ok {
   128  		if err := unmarshaler.UnmarshalText(data); err != nil {
   129  			return errors.Wrapf(err, "unmarshal text to %T failed", v)
   130  		}
   131  		return nil
   132  	}
   133  
   134  	if v == nil {
   135  		return UnmarshalText(reflect.ValueOf(v), data)
   136  	}
   137  
   138  	switch x := v.(type) {
   139  	case *[]byte:
   140  		var d []byte
   141  		if len(useBase64) > 0 && useBase64[0] {
   142  			var err error
   143  			d, err = FromBase64(data)
   144  			if err != nil {
   145  				return err
   146  			}
   147  		} else {
   148  			d = make([]byte, len(data))
   149  			copy(d, data)
   150  		}
   151  		*x = d
   152  	case *string:
   153  		*x = string(data)
   154  	case *bool:
   155  		v, err := strconv.ParseBool(string(data))
   156  		if err != nil {
   157  			return errors.Wrapf(err, "unmarshal text")
   158  		}
   159  		*x = v
   160  	case *int:
   161  		i, err := strconv.ParseInt(string(data), 10, 64)
   162  		if err != nil {
   163  			return errors.Wrap(err, "unmarshal text")
   164  		}
   165  		*x = int(i)
   166  	case *int8:
   167  		i, err := strconv.ParseInt(string(data), 10, 64)
   168  		if err != nil {
   169  			return errors.Wrap(err, "unmarshal text")
   170  		}
   171  		*x = int8(i)
   172  	case *int16:
   173  		i, err := strconv.ParseInt(string(data), 10, 64)
   174  		if err != nil {
   175  			return errors.Wrap(err, "unmarshal text")
   176  		}
   177  		*x = int16(i)
   178  	case *int32:
   179  		i, err := strconv.ParseInt(string(data), 10, 64)
   180  		if err != nil {
   181  			return errors.Wrap(err, "unmarshal text")
   182  		}
   183  		*x = int32(i)
   184  	case *int64:
   185  		i, err := strconv.ParseInt(string(data), 10, 64)
   186  		if err != nil {
   187  			return errors.Wrap(err, "unmarshal text")
   188  		}
   189  		*x = i
   190  	case *uint:
   191  		i, err := strconv.ParseUint(string(data), 10, 64)
   192  		if err != nil {
   193  			return errors.Wrap(err, "unmarshal text")
   194  		}
   195  		*x = uint(i)
   196  	case *uint8:
   197  		i, err := strconv.ParseUint(string(data), 10, 64)
   198  		if err != nil {
   199  			return errors.Wrap(err, "unmarshal text")
   200  		}
   201  		*x = uint8(i)
   202  	case *uint16:
   203  		i, err := strconv.ParseUint(string(data), 10, 64)
   204  		if err != nil {
   205  			return errors.Wrap(err, "unmarshal text")
   206  		}
   207  		*x = uint16(i)
   208  	case *uint32:
   209  		i, err := strconv.ParseUint(string(data), 10, 64)
   210  		if err != nil {
   211  			return errors.Wrap(err, "unmarshal text")
   212  		}
   213  		*x = uint32(i)
   214  	case *uint64:
   215  		i, err := strconv.ParseUint(string(data), 10, 64)
   216  		if err != nil {
   217  			return errors.Wrap(err, "unmarshal text")
   218  		}
   219  		*x = i
   220  	case *float32:
   221  		i, err := strconv.ParseFloat(string(data), 32)
   222  		if err != nil {
   223  			return errors.Wrap(err, "unmarshal text")
   224  		}
   225  		*x = float32(i)
   226  	case *float64:
   227  		i, err := strconv.ParseFloat(string(data), 64)
   228  		if err != nil {
   229  			return errors.Wrap(err, "unmarshal text")
   230  		}
   231  		*x = i
   232  	default:
   233  		return UnmarshalTextToReflectValue(reflect.ValueOf(x), data, useBase64...)
   234  	}
   235  	return nil
   236  }
   237  
   238  func UnmarshalTextToReflectValue(rv reflect.Value, data []byte, useBase64 ...bool) error {
   239  	if rv.Kind() != reflect.Ptr {
   240  		return errors.Errorf("unmarshal text need ptr value, but got %#v", rv.Interface())
   241  	}
   242  
   243  	for rv.Kind() == reflect.Ptr {
   244  		if rv.IsNil() {
   245  			rv.Set(NewReflectValue(rv.Type()))
   246  		}
   247  		rv = rv.Elem()
   248  	}
   249  
   250  	switch rv.Kind() {
   251  	case reflect.Slice:
   252  		elem := rv.Type().Elem()
   253  		if elem.Kind() == reflect.Uint8 && elem.PkgPath() == "" {
   254  			if len(useBase64) > 0 && useBase64[0] {
   255  				d, err := FromBase64(data)
   256  				if err != nil {
   257  					return err
   258  				}
   259  				rv.SetBytes(d)
   260  				return nil
   261  			}
   262  			rv.SetBytes(data)
   263  		}
   264  	case reflect.String:
   265  		rv.SetString(string(data))
   266  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   267  		intV, err := strconv.ParseInt(string(data), 10, 64)
   268  		if err != nil {
   269  			return errors.Wrap(err, "unmarshal text")
   270  		}
   271  		rv.SetInt(intV)
   272  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   273  		uintV, err := strconv.ParseUint(string(data), 10, 64)
   274  		if err != nil {
   275  			return errors.Wrap(err, "unmarshal text")
   276  		}
   277  		rv.SetUint(uintV)
   278  	case reflect.Float32, reflect.Float64:
   279  		floatV, err := strconv.ParseFloat(string(data), 64)
   280  		if err != nil {
   281  			return errors.Wrap(err, "unmarshal text")
   282  		}
   283  		rv.SetFloat(floatV)
   284  	case reflect.Bool:
   285  		boolV, err := strconv.ParseBool(string(data))
   286  		if err != nil {
   287  			return errors.Wrap(err, "unmarshal text")
   288  		}
   289  		rv.SetBool(boolV)
   290  	}
   291  	return nil
   292  }
   293  
   294  func NewReflectValue(t reflect.Type) reflect.Value {
   295  	v := reflect.New(t).Elem()
   296  	if t.Kind() == reflect.Ptr {
   297  		v.Set(NewReflectValue(t.Elem()).Addr())
   298  	}
   299  	return v
   300  }
   301  
   302  func ToBase64(raw []byte) []byte {
   303  	length := base64.StdEncoding.EncodedLen(len(raw))
   304  	if length <= 1024 {
   305  		d := make([]byte, length)
   306  		base64.StdEncoding.Encode(d, raw)
   307  		return d
   308  	}
   309  	b := bytes.NewBuffer(nil)
   310  	base64.NewDecoder(base64.StdEncoding, b)
   311  	return b.Bytes()
   312  }
   313  
   314  func FromBase64(data []byte) ([]byte, error) {
   315  	length := base64.StdEncoding.DecodedLen(len(data))
   316  	d := make([]byte, length)
   317  	n, err := base64.StdEncoding.Decode(d, data)
   318  	if err != nil {
   319  		return nil, err
   320  	}
   321  	return d[:n], nil
   322  }