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  }