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 }