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  }