gitlab.com/ignitionrobotics/web/ign-go@v1.0.0-rc4/reflect/reflect.go (about)

     1  package reflect
     2  
     3  import (
     4  	"errors"
     5  	"reflect"
     6  )
     7  
     8  var (
     9  	// ErrNotPointer is returned when a function receives a parameter that is not a pointer.
    10  	ErrNotPointer = errors.New("out value is not pointer")
    11  	// ErrNotCollection is returned when a function receives a parameter that is not a collection.
    12  	ErrNotCollection = errors.New("out value is not collection")
    13  	// ErrInvalidOutValue is returned when an out value cannot be set to the target value.
    14  	ErrInvalidOutValue = errors.New("invalid out value type")
    15  )
    16  
    17  // SetValue sets the `out` parameter to the specified value.
    18  // `out` must be a pointer.
    19  func SetValue(out interface{}, value interface{}) (err error) {
    20  	// Handle panics
    21  	defer func() {
    22  		if p := recover(); p != nil {
    23  			err = ErrInvalidOutValue
    24  		}
    25  	}()
    26  
    27  	// Get the pointer value
    28  	p := reflect.ValueOf(out)
    29  	if p.Kind() != reflect.Ptr {
    30  		return ErrNotPointer
    31  	}
    32  
    33  	v := reflect.ValueOf(value)
    34  	pv := p.Elem()
    35  	pv.Set(v)
    36  
    37  	return nil
    38  }
    39  
    40  // AppendToSlice appends values to a slice.
    41  // `out` must be a pointer to a slice.
    42  // `values` must be compatible with the slice type.
    43  func AppendToSlice(out interface{}, values ...interface{}) error {
    44  	// Get the pointer value
    45  	p := reflect.ValueOf(out)
    46  	if p.Kind() != reflect.Ptr {
    47  		return ErrNotPointer
    48  	}
    49  
    50  	// Get the slice value
    51  	v := p.Elem()
    52  	if v.Kind() != reflect.Slice {
    53  		return ErrNotCollection
    54  	}
    55  
    56  	// Append values to slice
    57  	for _, value := range values {
    58  		v.Set(reflect.Append(v, reflect.ValueOf(value)))
    59  	}
    60  
    61  	return nil
    62  }
    63  
    64  // SetMapValue sets a value in a map.
    65  // `out` must be a map.
    66  // `key` must be compatible with the map key type.
    67  // `value` must be compatible with the map value type.
    68  func SetMapValue(out interface{}, key interface{}, value interface{}) error {
    69  	// Get the map value
    70  	v := reflect.ValueOf(out)
    71  	if v.Kind() != reflect.Map {
    72  		return ErrNotCollection
    73  	}
    74  
    75  	// Set map value
    76  	v.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(value))
    77  
    78  	return nil
    79  }
    80  
    81  // NewInstance returns a new instance of the same type as the input value.
    82  // The returned value will contain the zero value of the type.
    83  func NewInstance(value interface{}) interface{} {
    84  	entity := reflect.ValueOf(value)
    85  
    86  	if entity.Kind() == reflect.Ptr {
    87  		entity = reflect.New(entity.Elem().Type())
    88  	} else {
    89  		entity = reflect.New(entity.Type()).Elem()
    90  	}
    91  
    92  	return entity.Interface()
    93  }
    94  
    95  // NewCollectionValueInstance receives a collection (slice, map) and returns a new instance of the collection's value
    96  // type. If the collection value type is a pointer type, a pointer object to a new instance of the type value is
    97  // returned.
    98  func NewCollectionValueInstance(collection interface{}) (interface{}, error) {
    99  	// Get the collection value
   100  	s := reflect.TypeOf(collection)
   101  	if s.Kind() != reflect.Slice && s.Kind() != reflect.Map {
   102  		return nil, ErrNotCollection
   103  	}
   104  
   105  	// Get the collection's value type
   106  	t := s.Elem()
   107  
   108  	// Create the collection element instance
   109  	var v reflect.Value
   110  	// If the value is a pointer, assign a value of the correct type
   111  	if t.Kind() == reflect.Ptr {
   112  		// Pointer value instance value
   113  		v = reflect.New(t.Elem())
   114  	} else {
   115  		v = reflect.New(t).Elem()
   116  	}
   117  
   118  	return v.Interface(), nil
   119  }