v0.0.147
This commit is contained in:
88
reflectext/primitiveStringSerializer.go
Normal file
88
reflectext/primitiveStringSerializer.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package reflectext
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// PrimitiveStringSerializer is used to serialize primitive types (and a few more) from and to string
|
||||
// This is not really intended to be user facing, and more as a simple building block for other mechanisms
|
||||
// supports:
|
||||
// - golang primitives (ints, uints, floats, bool, string)
|
||||
// - type aliases
|
||||
// - time.Time
|
||||
// - primitive.ObjectID
|
||||
type PrimitiveStringSerializer struct{}
|
||||
|
||||
func (pss PrimitiveStringSerializer) ValueToString(v any) (string, error) {
|
||||
|
||||
inType := reflect.TypeOf(v)
|
||||
|
||||
if inType.Kind() == reflect.Ptr && langext.IsNil(v) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
if inType.Kind() == reflect.Ptr {
|
||||
rval1 := reflect.ValueOf(v)
|
||||
rval2 := rval1.Elem()
|
||||
rval3 := rval2.Interface()
|
||||
return pss.ValueToString(rval3)
|
||||
}
|
||||
|
||||
if conv, ok := primitiveSerializer[inType]; ok {
|
||||
return conv.ToString(v)
|
||||
}
|
||||
|
||||
for convType, conv := range primitiveSerializer {
|
||||
if castV, ok := TryCastType(v, convType); ok {
|
||||
return conv.ToString(castV)
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.New(fmt.Sprintf("failed to find a matching generic <toString> conversion fo type %T", v))
|
||||
}
|
||||
|
||||
func (pss PrimitiveStringSerializer) ValueFromString(str string, outType reflect.Type) (any, error) {
|
||||
|
||||
if outType.Kind() == reflect.Ptr && str == "" {
|
||||
return reflect.Zero(outType).Interface(), nil // = nil.(outType), nil
|
||||
}
|
||||
|
||||
if outType.Kind() == reflect.Ptr {
|
||||
|
||||
innerValue, err := pss.ValueFromString(str, outType.Elem())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// this weird piece of shit converts innerValue to &innerValue (while keeping types)
|
||||
|
||||
rval1 := reflect.ValueOf(innerValue)
|
||||
rval2 := rval1.Convert(outType.Elem())
|
||||
rval3 := reflect.New(outType.Elem())
|
||||
rval3.Elem().Set(rval2)
|
||||
rval4 := rval3.Interface()
|
||||
|
||||
return rval4, nil
|
||||
}
|
||||
|
||||
if conv, ok := primitiveSerializer[outType]; ok {
|
||||
return conv.FromString(str)
|
||||
}
|
||||
|
||||
emptyResultVal := reflect.Zero(outType).Interface()
|
||||
|
||||
for convType, conv := range primitiveSerializer {
|
||||
if _, ok := TryCastType(emptyResultVal, convType); ok {
|
||||
if convVal, err := conv.FromString(str); err == nil {
|
||||
if resVal, ok := TryCastType(convVal, outType); ok {
|
||||
return resVal, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.New(fmt.Sprintf("failed to find a matching generic <toString> conversion fo type %s", outType.String()))
|
||||
}
|
Reference in New Issue
Block a user