github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/datacodec/injectors.go (about) 1 // Copyright 2021 DataStax 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package datacodec 16 17 import ( 18 "reflect" 19 ) 20 21 // A utility to inject elements in container types like slices, arrays, structs and maps, using a unified API. 22 type injector interface { 23 24 // zeroElem returns a pointer to a zero value for the element at the given key. 25 // Note that the returned value *must* be a pointer, even if the underlying element type is not, because the 26 // returned value will be passed to Codec.Decode. 27 zeroElem(index int, key interface{}) (value interface{}, err error) 28 29 // setElem sets the element at the given key to the given decoded value. 30 // Note that the decoded value will *always* be a pointer: if the underlying element type is not a pointer, the 31 // value needs to be passed through reflect.Indirect before being set. keyWasNull and valueWasNull indicate that the 32 // decoded key and value were CQL NULLs. 33 setElem(index int, key, value interface{}, keyWasNull, valueWasNull bool) error 34 } 35 36 // A utility to inject keys and values in maps. 37 type keyValueInjector interface { 38 injector 39 40 // zeroKey returns a pointer to a zero value for the map key type. 41 // Note that the returned value *must* be a pointer, even if the underlying key type is not, because the returned 42 // value will be passed to Codec.Decode. 43 zeroKey(index int) (value interface{}, err error) 44 } 45 46 type sliceInjector struct { 47 dest reflect.Value 48 } 49 50 type structInjector struct { 51 dest reflect.Value 52 fieldsByIndex map[int]reflect.Value 53 fieldsByName map[string]reflect.Value 54 } 55 56 type mapInjector struct { 57 dest reflect.Value 58 } 59 60 func newSliceInjector(dest reflect.Value) (injector, error) { 61 if !dest.IsValid() { 62 return nil, ErrDestinationTypeNotSupported 63 } else if dest.Kind() != reflect.Slice && dest.Kind() != reflect.Array { 64 return nil, errWrongContainerType("slice or array", dest.Type()) 65 } 66 return &sliceInjector{dest}, nil 67 68 } 69 func newStructInjector(dest reflect.Value) (keyValueInjector, error) { 70 if !dest.IsValid() { 71 return nil, ErrDestinationTypeNotSupported 72 } else if dest.Kind() != reflect.Struct { 73 return nil, errWrongContainerType("struct", dest.Type()) 74 } else if !dest.CanSet() { 75 return nil, errDestinationUnaddressable(dest) 76 } 77 return &structInjector{dest: dest}, nil 78 } 79 80 func newMapInjector(dest reflect.Value) (keyValueInjector, error) { 81 if !dest.IsValid() { 82 return nil, ErrDestinationTypeNotSupported 83 } else if dest.Kind() != reflect.Map { 84 return nil, errWrongContainerType("map", dest.Type()) 85 } 86 return &mapInjector{dest}, nil 87 } 88 89 func (i *sliceInjector) zeroElem(_ int, _ interface{}) (value interface{}, err error) { 90 zero := ensurePointer(nilSafeZero(i.dest.Type().Elem())) 91 return zero.Interface(), nil 92 } 93 94 func (i *sliceInjector) setElem(index int, _, value interface{}, _, valueWasNull bool) error { 95 if index < 0 || index >= i.dest.Len() { 96 return errSliceIndexOutOfRange(i.dest.Type().Kind() == reflect.Slice, index) 97 } 98 elementType := i.dest.Type().Elem() 99 if valueWasNull { 100 zero := reflect.Zero(elementType) 101 i.dest.Index(index).Set(zero) 102 } else { 103 newValue := maybeIndirect(elementType, reflect.ValueOf(value)) 104 if !newValue.Type().AssignableTo(elementType) { 105 if i.dest.Kind() == reflect.Slice { 106 return errWrongElementType("slice element", elementType, newValue.Type()) 107 } else { 108 return errWrongElementType("array element", elementType, newValue.Type()) 109 } 110 } 111 i.dest.Index(index).Set(newValue) 112 } 113 return nil 114 } 115 116 func (i *structInjector) zeroKey(_ int) (value interface{}, err error) { 117 return new(string), nil 118 } 119 120 func (i *structInjector) zeroElem(_ int, key interface{}) (interface{}, error) { 121 if field, err := i.locateAndStoreField(key); err != nil { 122 return nil, err 123 } else if field.IsValid() && field.CanSet() { 124 zero := ensurePointer(nilSafeZero(field.Type())) 125 return zero.Interface(), nil 126 } else { 127 return nil, errStructFieldInvalid(i.dest, key) 128 } 129 } 130 131 func (i *structInjector) setElem(_ int, key, value interface{}, _, valueWasNull bool) error { 132 field := i.retrieveStoredField(key) 133 if field.IsValid() && field.CanSet() { 134 fieldType := field.Type() 135 if valueWasNull { 136 zero := reflect.Zero(fieldType) 137 field.Set(zero) 138 } else { 139 newValue := maybeIndirect(fieldType, reflect.ValueOf(value)) 140 if !newValue.Type().AssignableTo(fieldType) { 141 return errWrongElementType("struct field value", fieldType, newValue.Type()) 142 } 143 field.Set(newValue) 144 } 145 return nil 146 } else { 147 return errStructFieldInvalid(i.dest, key) 148 } 149 } 150 151 func (i *structInjector) locateAndStoreField(key interface{}) (field reflect.Value, err error) { 152 switch k := key.(type) { 153 case string: 154 field = locateFieldByName(i.dest, k) 155 if i.fieldsByName == nil { 156 i.fieldsByName = map[string]reflect.Value{} 157 } 158 i.fieldsByName[k] = field 159 case *string: 160 return i.locateAndStoreField(*k) 161 case int: 162 field = locateFieldByIndex(i.dest, k) 163 if i.fieldsByIndex == nil { 164 i.fieldsByIndex = map[int]reflect.Value{} 165 } 166 i.fieldsByIndex[k] = field 167 default: 168 err = errWrongElementTypes("struct field key", typeOfInt, typeOfString, reflect.TypeOf(key)) 169 } 170 return 171 } 172 173 func (i *structInjector) retrieveStoredField(key interface{}) reflect.Value { 174 var field reflect.Value 175 switch k := key.(type) { 176 case string: 177 field = i.fieldsByName[k] 178 case *string: 179 field = i.fieldsByName[*k] 180 case int: 181 field = i.fieldsByIndex[k] 182 } 183 return field 184 } 185 186 func (i *mapInjector) zeroKey(_ int) (interface{}, error) { 187 zero := ensurePointer(nilSafeZero(i.dest.Type().Key())) 188 return zero.Interface(), nil 189 } 190 191 func (i *mapInjector) zeroElem(_ int, _ interface{}) (interface{}, error) { 192 zero := ensurePointer(nilSafeZero(i.dest.Type().Elem())) 193 return zero.Interface(), nil 194 } 195 196 func (i *mapInjector) setElem(_ int, key, value interface{}, keyWasNull, valueWasNull bool) error { 197 keyType := i.dest.Type().Key() 198 var newKey reflect.Value 199 if keyWasNull { 200 newKey = reflect.Zero(keyType) 201 } else { 202 newKey = maybeIndirect(keyType, reflect.ValueOf(key)) 203 if !newKey.Type().AssignableTo(keyType) { 204 return errWrongElementType("map key", keyType, newKey.Type()) 205 } 206 } 207 valueType := i.dest.Type().Elem() 208 var newValue reflect.Value 209 if valueWasNull { 210 newValue = reflect.Zero(valueType) 211 } else { 212 newValue = maybeIndirect(valueType, reflect.ValueOf(value)) 213 if !newValue.Type().AssignableTo(valueType) { 214 return errWrongElementType("map value", valueType, newValue.Type()) 215 } 216 } 217 i.dest.SetMapIndex(newKey, newValue) 218 return nil 219 }