Files
obitools4/pkg/obiutils/cast_interface.go

299 lines
7.0 KiB
Go

package obiutils
import (
"fmt"
"maps"
"reflect"
"strconv"
"strings"
log "github.com/sirupsen/logrus"
)
// InterfaceToString converts an interface value to a string.
//
// The function takes an interface{} value as a parameter and returns a string representation of that value.
// It returns the string representation and an error if any occurred during the conversion process.
func InterfaceToString(i interface{}) (val string, err error) {
err = nil
if vc, ok := i.(interface{ String() string }); ok {
val = vc.String()
} else {
val = fmt.Sprintf("%v", i)
}
return
}
// CastableToInt checks if the given input can be casted to an integer.
//
// i: the value to check for castability.
// bool: true if the value can be casted to an integer, false otherwise.
func CastableToInt(i interface{}) bool {
switch i.(type) {
case int,
int8, int16, int32, int64,
float32, float64,
uint8, uint16, uint32, uint64:
return true
default:
return false
}
}
// InterfaceToBool converts an interface value to a boolean.
//
// It takes an interface{} as a parameter and returns a boolean value and an error.
func InterfaceToBool(i interface{}) (val bool, err error) {
err = nil
val = false
switch t := i.(type) {
case bool:
val = t
case int:
val = t != 0
case int8:
val = t != 0 // standardizes across systems
case int16:
val = t != 0 // standardizes across systems
case int32:
val = t != 0 // standardizes across systems
case int64:
val = t != 0 // standardizes across systems
case float32:
val = t != 0 // standardizes across systems
case float64:
val = t != 0 // standardizes across systems
case uint8:
val = t != 0 // standardizes across systems
case uint16:
val = t != 0 // standardizes across systems
case uint32:
val = t != 0 // standardizes across systems
case uint64:
val = t != 0 // standardizes across systems
case string:
val = strings.ToLower(t) == "true" || t == "1" || strings.ToLower(t) == "yes" || strings.ToLower(t) == "on" || strings.ToLower(t) == "t"
case nil:
val = false
default:
err = &NotABoolean{"value attribute cannot be casted to a boolean"}
}
return
}
// MapToMapInterface converts a map to a map of type map[string]interface{}.
//
// It takes an interface{} parameter `m` which represents the map to be converted.
//
// It returns a map[string]interface{} which is the converted map. If the input map is not of type map[string]interface{},
// it panics and logs an error message.
func MapToMapInterface(m interface{}) map[string]interface{} {
type hasMap interface {
Map() map[string]int
RLock()
RUnlock()
Len() int
}
if v, ok := m.(hasMap); ok {
val := make(map[string]interface{}, v.Len())
v.RLock()
defer v.RUnlock()
for k, v := range v.Map() {
val[k] = v
}
} else if IsAMap(m) {
reflectMap := reflect.ValueOf(m)
keys := reflectMap.MapKeys()
val := make(map[string]interface{}, len(keys))
for k := range keys {
val[keys[k].String()] = reflectMap.MapIndex(keys[k]).Interface()
}
return val
}
log.Panic("Invalid map type")
return make(map[string]interface{})
}
// InterfaceToInt converts a interface{} to an integer value if possible.
// If not a "NotAnInteger" error is returned via the err
// return value and val is set to 0.
func InterfaceToInt(i interface{}) (val int, err error) {
err = nil
val = 0
switch t := i.(type) {
case int:
val = t
case int8:
val = int(t) // standardizes across systems
case int16:
val = int(t) // standardizes across systems
case int32:
val = int(t) // standardizes across systems
case int64:
val = int(t) // standardizes across systems
case float32:
val = int(t) // standardizes across systems
case float64:
val = int(t) // standardizes across systems
case uint8:
val = int(t) // standardizes across systems
case uint16:
val = int(t) // standardizes across systems
case uint32:
val = int(t) // standardizes across systems
case uint64:
val = int(t) // standardizes across systems
case string:
rep, err := strconv.ParseInt(t, 10, 64)
if err != nil {
err = &NotAnFloat64{"value attribute cannot be casted to an int value"}
}
val = int(rep)
default:
err = &NotAnInteger{"value attribute cannot be casted to an integer"}
}
return
}
// InterfaceToInt converts a interface{} to an integer value if possible.
// If not a "NotAnInteger" error is returned via the err
// return value and val is set to 0.
func InterfaceToFloat64(i interface{}) (val float64, err error) {
err = nil
val = 0
switch t := i.(type) {
case int:
val = float64(t)
case int8:
val = float64(t) // standardizes across systems
case int16:
val = float64(t) // standardizes across systems
case int32:
val = float64(t) // standardizes across systems
case int64:
val = float64(t) // standardizes across systems
case float32:
val = float64(t) // standardizes across systems
case float64:
val = t // standardizes across systems
case uint8:
val = float64(t) // standardizes across systems
case uint16:
val = float64(t) // standardizes across systems
case uint32:
val = float64(t) // standardizes across systems
case uint64:
val = float64(t) // standardizes across systems
case string:
val, err = strconv.ParseFloat(t, 10)
if err != nil {
err = &NotAnFloat64{"value attribute cannot be casted to a float value"}
}
default:
err = &NotAnFloat64{"value attribute cannot be casted to a float value"}
}
return
}
func InterfaceToIntMap(i interface{}) (val map[string]int, err error) {
err = nil
type hasMap interface {
Map() map[string]int
RLock()
RUnlock()
}
switch i := i.(type) {
case map[string]int:
val = i
case hasMap:
i.RLock()
defer i.RUnlock()
val = maps.Clone(i.Map())
case map[string]interface{}:
val = make(map[string]int, len(i))
for k, v := range i {
val[k], err = InterfaceToInt(v)
if err != nil {
return
}
}
case map[string]float64:
val = make(map[string]int, len(i))
for k, v := range i {
val[k] = int(v)
}
default:
err = &NotAMapInt{"value attribute cannot be casted to a map[string]int"}
}
return
}
func InterfaceToStringMap(i interface{}) (val map[string]string, err error) {
err = nil
type hasMap interface {
Map() map[string]int
RLock()
RUnlock()
Len() int
}
switch i := i.(type) {
case map[string]string:
val = i
case hasMap:
val = make(map[string]string, i.Len())
i.RLock()
defer i.RUnlock()
for k, v := range i.Map() {
val[k] = strconv.Itoa(v)
}
case map[string]interface{}:
val = make(map[string]string, len(i))
for k, v := range i {
val[k], err = InterfaceToString(v)
if err != nil {
return
}
}
default:
err = &NotAMapInt{"value attribute cannot be casted to a map[string]int"}
}
return
}
func InterfaceToStringSlice(i interface{}) (val []string, err error) {
err = nil
switch i := i.(type) {
case []string:
val = i
case []interface{}:
val = make([]string, len(i))
for k, v := range i {
val[k], err = InterfaceToString(v)
if err != nil {
return
}
}
default:
err = &NotAMapInt{"value attribute cannot be casted to a []string"}
}
return
}