github.com/viant/toolbox@v0.34.5/types.go (about)

     1  package toolbox
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"time"
     7  )
     8  
     9  //Zeroable represents object that can call IsZero
    10  type Zeroable interface {
    11  	//IsZero returns true, if value of object was zeroed.
    12  	IsZero() bool
    13  }
    14  
    15  //IsInt returns true if input is an int
    16  func IsInt(input interface{}) bool {
    17  	switch input.(type) {
    18  	case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
    19  		return true
    20  	}
    21  	return false
    22  }
    23  
    24  //IsNumber returns true if type is either float or int
    25  func IsNumber(input interface{}) bool {
    26  	return IsFloat(input) || IsInt(input)
    27  }
    28  
    29  //IsFloat returns true if input is a float
    30  func IsFloat(input interface{}) bool {
    31  	switch input.(type) {
    32  	case float32, float64:
    33  		return true
    34  	}
    35  	return false
    36  }
    37  
    38  //IsBool returns true if input is a boolean
    39  func IsBool(input interface{}) bool {
    40  	switch input.(type) {
    41  	case bool:
    42  		return true
    43  	}
    44  	return false
    45  }
    46  
    47  //IsString returns true if input is a string
    48  func IsString(input interface{}) bool {
    49  	switch input.(type) {
    50  	case string:
    51  		return true
    52  	}
    53  	return false
    54  }
    55  
    56  //CanConvertToString checks if  input can be converted to string
    57  func CanConvertToString(input interface{}) bool {
    58  	return reflect.TypeOf(input).AssignableTo(reflect.TypeOf(""))
    59  }
    60  
    61  //IsTime returns true if input is a time
    62  func IsTime(input interface{}) bool {
    63  	switch input.(type) {
    64  	case time.Time:
    65  		return true
    66  	case *time.Time:
    67  		return true
    68  	}
    69  	return false
    70  }
    71  
    72  //IsMap returns true if input is a map
    73  func IsMap(input interface{}) bool {
    74  	switch input.(type) {
    75  	case map[string]interface{}:
    76  		return true
    77  	}
    78  	candidateType := DereferenceType(reflect.TypeOf(input))
    79  	return candidateType.Kind() == reflect.Map
    80  }
    81  
    82  //IsStruct returns true if input is a map
    83  func IsStruct(input interface{}) bool {
    84  	if input == nil {
    85  		return false
    86  	}
    87  	inputType := DereferenceType(input)
    88  	return inputType.Kind() == reflect.Struct
    89  }
    90  
    91  //IsSlice returns true if input is a map
    92  func IsSlice(input interface{}) bool {
    93  	switch input.(type) {
    94  	case []interface{}:
    95  		return true
    96  	case []string:
    97  		return true
    98  	}
    99  	candidateType := DereferenceType(reflect.TypeOf(input))
   100  	return candidateType.Kind() == reflect.Slice
   101  }
   102  
   103  //IsFunc returns true if input is a funct
   104  func IsFunc(input interface{}) bool {
   105  	candidateType := DereferenceType(reflect.TypeOf(input))
   106  	return candidateType.Kind() == reflect.Func
   107  }
   108  
   109  //IsZero returns true if input is a zeroable
   110  func IsZero(input interface{}) bool {
   111  	if zeroable, ok := input.(Zeroable); ok {
   112  		return zeroable.IsZero()
   113  	}
   114  	return false
   115  }
   116  
   117  //IsPointer returns true if input is a pointer
   118  func IsPointer(input interface{}) bool {
   119  	if reflectType, ok := input.(reflect.Type); ok {
   120  		return reflectType.Kind() == reflect.Ptr
   121  	}
   122  	return reflect.TypeOf(input).Kind() == reflect.Ptr
   123  }
   124  
   125  //AssertPointerKind checks if input is a pointer of the passed in kind, if not it panic with message including name
   126  func AssertPointerKind(input interface{}, kind reflect.Kind, name string) {
   127  	AssertTypeKind(reflect.TypeOf(input), reflect.Ptr, name)
   128  	AssertTypeKind(reflect.TypeOf(input).Elem(), kind, name)
   129  }
   130  
   131  //AssertKind checks if input is of the passed in kind, if not it panic with message including name
   132  func AssertKind(input interface{}, kind reflect.Kind, name string) {
   133  	AssertTypeKind(reflect.TypeOf(input), kind, name)
   134  }
   135  
   136  //AssertTypeKind checks if dataType is of the passed in kind, if not it panic with message including name
   137  func AssertTypeKind(dataType reflect.Type, kind reflect.Kind, name string) {
   138  	if dataType.Kind() != kind {
   139  		panic(fmt.Sprintf("failed to check: %v - expected kind: %v but found %v (%v)", name, kind.String(), dataType.Kind(), dataType.String()))
   140  	}
   141  }
   142  
   143  //DiscoverValueByKind returns unwrapped input that matches expected kind, or panic if this is not possible
   144  func DiscoverValueByKind(input interface{}, expected reflect.Kind) reflect.Value {
   145  	result, err := TryDiscoverValueByKind(input, expected)
   146  	if err == nil {
   147  		return result
   148  	}
   149  	panic(err)
   150  }
   151  
   152  //TryDiscoverValueByKind returns unwrapped input that matches expected kind, or panic if this is not possible
   153  func TryDiscoverValueByKind(input interface{}, expected reflect.Kind) (reflect.Value, error) {
   154  	value, ok := input.(reflect.Value)
   155  	if !ok {
   156  		value = reflect.ValueOf(input)
   157  	}
   158  	if value.Kind() == expected {
   159  		return value, nil
   160  	} else if value.Kind() == reflect.Ptr {
   161  		return TryDiscoverValueByKind(value.Elem(), expected)
   162  	} else if value.Kind() == reflect.Interface {
   163  		return TryDiscoverValueByKind(value.Elem(), expected)
   164  	}
   165  	return value, fmt.Errorf("failed to discover value by kind expected: %v, actual:%T   on %v:", expected.String(), value.Type(), value)
   166  }
   167  
   168  //IsValueOfKind returns true if passed in input is of supplied kind.
   169  func IsValueOfKind(input interface{}, kind reflect.Kind) bool {
   170  	value, ok := input.(reflect.Value)
   171  	if !ok {
   172  		value = reflect.ValueOf(input)
   173  	}
   174  	if value.Kind() == kind {
   175  		return true
   176  	} else if value.Kind() == reflect.Ptr {
   177  		return IsValueOfKind(value.Elem(), kind)
   178  	} else if value.Kind() == reflect.Interface {
   179  		return IsValueOfKind(value.Elem(), kind)
   180  	}
   181  	return false
   182  }
   183  
   184  //DiscoverTypeByKind returns unwrapped input type that matches expected kind, or panic if this is not possible
   185  func DiscoverTypeByKind(input interface{}, expected reflect.Kind) reflect.Type {
   186  	result, err := TryDiscoverTypeByKind(input, expected)
   187  	if err != nil {
   188  		panic(err)
   189  	}
   190  	return result
   191  }
   192  
   193  //TryDiscoverTypeByKind returns unwrapped input type that matches expected kind, or error
   194  func TryDiscoverTypeByKind(input interface{}, expected reflect.Kind) (reflect.Type, error) {
   195  	value, ok := input.(reflect.Type)
   196  	if !ok {
   197  		value = reflect.TypeOf(input)
   198  	}
   199  	if value.Kind() == expected {
   200  		return value, nil
   201  	} else if value.Kind() == reflect.Ptr || value.Kind() == reflect.Slice {
   202  		return TryDiscoverTypeByKind(value.Elem(), expected)
   203  	}
   204  	return nil, fmt.Errorf("failed to discover type by kind %v, on %v:", expected.String(), value)
   205  }
   206  
   207  //DiscoverComponentType returns type unwrapped from pointer, slice or map
   208  func DiscoverComponentType(input interface{}) reflect.Type {
   209  	valueType, ok := input.(reflect.Type)
   210  	if !ok {
   211  		valueType = reflect.TypeOf(input)
   212  	}
   213  	if valueType.Kind() == reflect.Ptr {
   214  		return DiscoverComponentType(valueType.Elem())
   215  	} else if valueType.Kind() == reflect.Slice {
   216  		return valueType.Elem()
   217  	} else if valueType.Kind() == reflect.Map {
   218  		return valueType.Elem()
   219  	}
   220  	return valueType
   221  }