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 }