github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/datacodec/bigint.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 "math/big" 20 "strconv" 21 22 "github.com/datastax/go-cassandra-native-protocol/datatype" 23 "github.com/datastax/go-cassandra-native-protocol/primitive" 24 ) 25 26 // Bigint is a codec for the CQL bigint type. Its preferred Go type is int64, but it can encode from and decode 27 // to most numeric types, including big.Int. Note: contrary to what the name similarity suggests, bigint codecs cannot 28 // handle all possible big.Int values; the best CQL type for handling big.Int is varint, not bigint. 29 var Bigint Codec = &bigintCodec{dataType: datatype.Bigint} 30 31 // Counter is a codec for the CQL counter type. Its preferred Go type is int64, but it can encode from and 32 // decode to most numeric types, including big.Int. Note: contrary to what the name similarity suggests, bigint codecs 33 // cannot handle all possible big.Int values; the best CQL type for handling big.Int is varint, not bigint. 34 var Counter Codec = &bigintCodec{dataType: datatype.Counter} 35 36 type bigintCodec struct { 37 dataType *datatype.PrimitiveType 38 } 39 40 func (c *bigintCodec) DataType() datatype.DataType { 41 return c.dataType 42 } 43 44 func (c *bigintCodec) Encode(source interface{}, version primitive.ProtocolVersion) (dest []byte, err error) { 45 var val int64 46 var wasNil bool 47 if val, wasNil, err = convertToInt64(source); err == nil && !wasNil { 48 dest = writeInt64(val) 49 } 50 if err != nil { 51 err = errCannotEncode(source, c.DataType(), version, err) 52 } 53 return 54 } 55 56 func (c *bigintCodec) Decode(source []byte, dest interface{}, version primitive.ProtocolVersion) (wasNull bool, err error) { 57 var val int64 58 if val, wasNull, err = readInt64(source); err == nil { 59 err = convertFromInt64(val, wasNull, dest) 60 } 61 if err != nil { 62 err = errCannotDecode(dest, c.DataType(), version, err) 63 } 64 return 65 } 66 67 func convertToInt64(source interface{}) (val int64, wasNil bool, err error) { 68 switch s := source.(type) { 69 case int: 70 val = int64(s) 71 case int64: 72 val = s 73 case int32: 74 val = int64(s) 75 case int16: 76 val = int64(s) 77 case int8: 78 val = int64(s) 79 case uint: 80 val, err = uintToInt64(s) 81 case uint64: 82 val, err = uint64ToInt64(s) 83 case uint32: 84 val = int64(s) 85 case uint16: 86 val = int64(s) 87 case uint8: 88 val = int64(s) 89 case string: 90 val, err = stringToInt64(s) 91 case *int: 92 if wasNil = s == nil; !wasNil { 93 val = int64(*s) 94 } 95 case *int64: 96 if wasNil = s == nil; !wasNil { 97 val = *s 98 } 99 case *int32: 100 if wasNil = s == nil; !wasNil { 101 val = int64(*s) 102 } 103 case *int16: 104 if wasNil = s == nil; !wasNil { 105 val = int64(*s) 106 } 107 case *int8: 108 if wasNil = s == nil; !wasNil { 109 val = int64(*s) 110 } 111 case *uint: 112 if wasNil = s == nil; !wasNil { 113 val, err = uintToInt64(*s) 114 } 115 case *uint64: 116 if wasNil = s == nil; !wasNil { 117 val, err = uint64ToInt64(*s) 118 } 119 case *uint32: 120 if wasNil = s == nil; !wasNil { 121 val = int64(*s) 122 } 123 case *uint16: 124 if wasNil = s == nil; !wasNil { 125 val = int64(*s) 126 } 127 case *uint8: 128 if wasNil = s == nil; !wasNil { 129 val = int64(*s) 130 } 131 case *big.Int: 132 // Note: non-pointer big.Int is not supported as per its docs, it should always be a pointer. 133 if wasNil = s == nil; !wasNil { 134 val, err = bigIntToInt64(s) 135 } 136 case *string: 137 if wasNil = s == nil; !wasNil { 138 val, err = stringToInt64(*s) 139 } 140 case nil: 141 wasNil = true 142 default: 143 err = ErrConversionNotSupported 144 } 145 if err != nil { 146 err = errSourceConversionFailed(source, val, err) 147 } 148 return 149 } 150 151 func convertFromInt64(val int64, wasNull bool, dest interface{}) (err error) { 152 switch d := dest.(type) { 153 case *interface{}: 154 if d == nil { 155 err = ErrNilDestination 156 } else if wasNull { 157 *d = nil 158 } else { 159 *d = val 160 } 161 case *int64: 162 if d == nil { 163 err = ErrNilDestination 164 } else if wasNull { 165 *d = 0 166 } else { 167 *d = val 168 } 169 case *int: 170 if d == nil { 171 err = ErrNilDestination 172 } else if wasNull { 173 *d = 0 174 } else { 175 *d, err = int64ToInt(val, strconv.IntSize) 176 } 177 case *int32: 178 if d == nil { 179 err = ErrNilDestination 180 } else if wasNull { 181 *d = 0 182 } else { 183 *d, err = int64ToInt32(val) 184 } 185 case *int16: 186 if d == nil { 187 err = ErrNilDestination 188 } else if wasNull { 189 *d = 0 190 } else { 191 *d, err = int64ToInt16(val) 192 } 193 case *int8: 194 if d == nil { 195 err = ErrNilDestination 196 } else if wasNull { 197 *d = 0 198 } else { 199 *d, err = int64ToInt8(val) 200 } 201 case *uint64: 202 if d == nil { 203 err = ErrNilDestination 204 } else if wasNull { 205 *d = 0 206 } else { 207 *d, err = int64ToUint64(val) 208 } 209 case *uint: 210 if d == nil { 211 err = ErrNilDestination 212 } else if wasNull { 213 *d = 0 214 } else { 215 *d, err = int64ToUint(val, strconv.IntSize) 216 } 217 case *uint32: 218 if d == nil { 219 err = ErrNilDestination 220 } else if wasNull { 221 *d = 0 222 } else { 223 *d, err = int64ToUint32(val) 224 } 225 case *uint16: 226 if d == nil { 227 err = ErrNilDestination 228 } else if wasNull { 229 *d = 0 230 } else { 231 *d, err = int64ToUint16(val) 232 } 233 case *uint8: 234 if d == nil { 235 err = ErrNilDestination 236 } else if wasNull { 237 *d = 0 238 } else { 239 *d, err = int64ToUint8(val) 240 } 241 case *big.Int: 242 if d == nil { 243 err = ErrNilDestination 244 } else if wasNull { 245 *d = big.Int{} 246 } else { 247 d.SetInt64(val) 248 } 249 case *string: 250 if d == nil { 251 err = ErrNilDestination 252 } else if wasNull { 253 *d = "" 254 } else { 255 *d = strconv.FormatInt(val, 10) 256 } 257 default: 258 err = errDestinationInvalid(dest) 259 } 260 if err != nil { 261 err = errDestinationConversionFailed(val, dest, err) 262 } 263 return 264 } 265 266 func writeInt64(val int64) (dest []byte) { 267 dest = make([]byte, primitive.LengthOfLong) 268 binary.BigEndian.PutUint64(dest, uint64(val)) 269 return 270 } 271 272 func readInt64(source []byte) (val int64, wasNull bool, err error) { 273 length := len(source) 274 if length == 0 { 275 wasNull = true 276 } else if length != primitive.LengthOfLong { 277 err = errWrongFixedLength(primitive.LengthOfLong, length) 278 } else { 279 val = int64(binary.BigEndian.Uint64(source)) 280 } 281 if err != nil { 282 err = errCannotRead(val, err) 283 } 284 return 285 }