github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/datacodec/smallint.go (about)

     1  // Copyright 2020 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  	"encoding/binary"
    19  	"strconv"
    20  
    21  	"github.com/datastax/go-cassandra-native-protocol/datatype"
    22  	"github.com/datastax/go-cassandra-native-protocol/primitive"
    23  )
    24  
    25  // Smallint is a codec for the CQL smallint type. Its preferred Go type is int16, but it can encode from and
    26  // decode to most numeric types.
    27  var Smallint Codec = &smallintCodec{}
    28  
    29  type smallintCodec struct{}
    30  
    31  func (c *smallintCodec) DataType() datatype.DataType {
    32  	return datatype.Smallint
    33  }
    34  
    35  func (c *smallintCodec) Encode(source interface{}, version primitive.ProtocolVersion) (dest []byte, err error) {
    36  	if !version.SupportsDataType(c.DataType().Code()) {
    37  		err = errDataTypeNotSupported(c.DataType(), version)
    38  	} else {
    39  		var val int16
    40  		var wasNil bool
    41  		if val, wasNil, err = convertToInt16(source); err == nil && !wasNil {
    42  			dest = writeInt16(val)
    43  		}
    44  	}
    45  	if err != nil {
    46  		err = errCannotEncode(source, c.DataType(), version, err)
    47  	}
    48  	return
    49  }
    50  
    51  func (c *smallintCodec) Decode(source []byte, dest interface{}, version primitive.ProtocolVersion) (wasNull bool, err error) {
    52  	if !version.SupportsDataType(c.DataType().Code()) {
    53  		wasNull = len(source) == 0
    54  		err = errDataTypeNotSupported(c.DataType(), version)
    55  	} else {
    56  		var val int16
    57  		if val, wasNull, err = readInt16(source); err == nil {
    58  			err = convertFromInt16(val, wasNull, dest)
    59  		}
    60  	}
    61  	if err != nil {
    62  		err = errCannotDecode(dest, c.DataType(), version, err)
    63  	}
    64  	return
    65  }
    66  
    67  func convertToInt16(source interface{}) (val int16, wasNil bool, err error) {
    68  	switch s := source.(type) {
    69  	case int64:
    70  		val, err = int64ToInt16(s)
    71  	case int:
    72  		val, err = intToInt16(s)
    73  	case int32:
    74  		val, err = int32ToInt16(s)
    75  	case int16:
    76  		val = s
    77  	case int8:
    78  		val = int16(s)
    79  	case uint64:
    80  		val, err = uint64ToInt16(s)
    81  	case uint:
    82  		val, err = uintToInt16(s)
    83  	case uint32:
    84  		val, err = uint32ToInt16(s)
    85  	case uint16:
    86  		val, err = uint16ToInt16(s)
    87  	case uint8:
    88  		val = int16(s)
    89  	case string:
    90  		val, err = stringToInt16(s)
    91  	case *int64:
    92  		if wasNil = s == nil; !wasNil {
    93  			val, err = int64ToInt16(*s)
    94  		}
    95  	case *int:
    96  		if wasNil = s == nil; !wasNil {
    97  			val, err = intToInt16(*s)
    98  		}
    99  	case *int32:
   100  		if wasNil = s == nil; !wasNil {
   101  			val, err = int32ToInt16(*s)
   102  		}
   103  	case *int16:
   104  		if wasNil = s == nil; !wasNil {
   105  			val = *s
   106  		}
   107  	case *int8:
   108  		if wasNil = s == nil; !wasNil {
   109  			val = int16(*s)
   110  		}
   111  	case *uint64:
   112  		if wasNil = s == nil; !wasNil {
   113  			val, err = uint64ToInt16(*s)
   114  		}
   115  	case *uint:
   116  		if wasNil = s == nil; !wasNil {
   117  			val, err = uintToInt16(*s)
   118  		}
   119  	case *uint32:
   120  		if wasNil = s == nil; !wasNil {
   121  			val, err = uint32ToInt16(*s)
   122  		}
   123  	case *uint16:
   124  		if wasNil = s == nil; !wasNil {
   125  			val, err = uint16ToInt16(*s)
   126  		}
   127  	case *uint8:
   128  		if wasNil = s == nil; !wasNil {
   129  			val = int16(*s)
   130  		}
   131  	case *string:
   132  		if wasNil = s == nil; !wasNil {
   133  			val, err = stringToInt16(*s)
   134  		}
   135  	case nil:
   136  		wasNil = true
   137  	default:
   138  		err = ErrConversionNotSupported
   139  	}
   140  	if err != nil {
   141  		err = errSourceConversionFailed(source, val, err)
   142  	}
   143  	return
   144  }
   145  
   146  func convertFromInt16(val int16, wasNull bool, dest interface{}) (err error) {
   147  	switch d := dest.(type) {
   148  	case *interface{}:
   149  		if d == nil {
   150  			err = ErrNilDestination
   151  		} else if wasNull {
   152  			*d = nil
   153  		} else {
   154  			*d = val
   155  		}
   156  	case *int64:
   157  		if d == nil {
   158  			err = ErrNilDestination
   159  		} else if wasNull {
   160  			*d = 0
   161  		} else {
   162  			*d = int64(val)
   163  		}
   164  	case *int:
   165  		if d == nil {
   166  			err = ErrNilDestination
   167  		} else if wasNull {
   168  			*d = 0
   169  		} else {
   170  			*d = int(val)
   171  		}
   172  	case *int32:
   173  		if d == nil {
   174  			err = ErrNilDestination
   175  		} else if wasNull {
   176  			*d = 0
   177  		} else {
   178  			*d = int32(val)
   179  		}
   180  	case *int16:
   181  		if d == nil {
   182  			err = ErrNilDestination
   183  		} else if wasNull {
   184  			*d = 0
   185  		} else {
   186  			*d = val
   187  		}
   188  	case *int8:
   189  		if d == nil {
   190  			err = ErrNilDestination
   191  		} else if wasNull {
   192  			*d = 0
   193  		} else {
   194  			*d, err = int16ToInt8(val)
   195  		}
   196  	case *uint64:
   197  		if d == nil {
   198  			err = ErrNilDestination
   199  		} else if wasNull {
   200  			*d = 0
   201  		} else {
   202  			*d, err = int16ToUint64(val)
   203  		}
   204  	case *uint:
   205  		if d == nil {
   206  			err = ErrNilDestination
   207  		} else if wasNull {
   208  			*d = 0
   209  		} else {
   210  			*d, err = int16ToUint(val)
   211  		}
   212  	case *uint32:
   213  		if d == nil {
   214  			err = ErrNilDestination
   215  		} else if wasNull {
   216  			*d = 0
   217  		} else {
   218  			*d, err = int16ToUint32(val)
   219  		}
   220  	case *uint16:
   221  		if d == nil {
   222  			err = ErrNilDestination
   223  		} else if wasNull {
   224  			*d = 0
   225  		} else {
   226  			*d, err = int16ToUint16(val)
   227  		}
   228  	case *uint8:
   229  		if d == nil {
   230  			err = ErrNilDestination
   231  		} else if wasNull {
   232  			*d = 0
   233  		} else {
   234  			*d, err = int16ToUint8(val)
   235  		}
   236  	case *string:
   237  		if d == nil {
   238  			err = ErrNilDestination
   239  		} else if wasNull {
   240  			*d = ""
   241  		} else {
   242  			*d = strconv.FormatInt(int64(val), 10)
   243  		}
   244  	default:
   245  		err = errDestinationInvalid(dest)
   246  	}
   247  	if err != nil {
   248  		err = errDestinationConversionFailed(val, dest, err)
   249  	}
   250  	return
   251  }
   252  
   253  func writeInt16(val int16) (dest []byte) {
   254  	dest = make([]byte, primitive.LengthOfShort)
   255  	binary.BigEndian.PutUint16(dest, uint16(val))
   256  	return
   257  }
   258  
   259  func readInt16(source []byte) (val int16, wasNull bool, err error) {
   260  	length := len(source)
   261  	if length == 0 {
   262  		wasNull = true
   263  	} else if length != primitive.LengthOfShort {
   264  		err = errWrongFixedLength(primitive.LengthOfShort, length)
   265  	} else {
   266  		val = int16(binary.BigEndian.Uint16(source))
   267  	}
   268  	if err != nil {
   269  		err = errCannotRead(val, err)
   270  	}
   271  	return
   272  }