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 }