github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/datacodec/tinyint.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  	"math"
    19  	"strconv"
    20  
    21  	"github.com/datastax/go-cassandra-native-protocol/datatype"
    22  	"github.com/datastax/go-cassandra-native-protocol/primitive"
    23  )
    24  
    25  // Tinyint is a codec for the CQL tinyint type. Its preferred Go type is int8, but it can encode from and decode
    26  // to most numeric types.
    27  var Tinyint Codec = &tinyintCodec{}
    28  
    29  type tinyintCodec struct{}
    30  
    31  func (c *tinyintCodec) DataType() datatype.DataType {
    32  	return datatype.Tinyint
    33  }
    34  
    35  func (c *tinyintCodec) 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 int8
    40  		var wasNil bool
    41  		if val, wasNil, err = convertToInt8(source); err == nil && !wasNil {
    42  			dest = writeInt8(val)
    43  		}
    44  	}
    45  	if err != nil {
    46  		err = errCannotEncode(source, c.DataType(), version, err)
    47  	}
    48  	return
    49  }
    50  
    51  func (c *tinyintCodec) 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 int8
    57  		if val, wasNull, err = readInt8(source); err == nil {
    58  			err = convertFromInt8(val, wasNull, dest)
    59  		}
    60  	}
    61  	if err != nil {
    62  		err = errCannotDecode(dest, c.DataType(), version, err)
    63  	}
    64  	return
    65  }
    66  
    67  func convertToInt8(source interface{}) (val int8, wasNil bool, err error) {
    68  	switch s := source.(type) {
    69  	case int64:
    70  		val, err = int64ToInt8(s)
    71  	case int:
    72  		val, err = intToInt8(s)
    73  	case int32:
    74  		val, err = int32ToInt8(s)
    75  	case int16:
    76  		val, err = int16ToInt8(s)
    77  	case int8:
    78  		val = s
    79  	case uint64:
    80  		val, err = uint64ToInt8(s)
    81  	case uint:
    82  		val, err = uintToInt8(s)
    83  	case uint32:
    84  		val, err = uint32ToInt8(s)
    85  	case uint16:
    86  		val, err = uint16ToInt8(s)
    87  	case uint8:
    88  		val, err = uint8ToInt8(s)
    89  	case string:
    90  		val, err = stringToInt8(s)
    91  	case *int64:
    92  		if wasNil = s == nil; !wasNil {
    93  			val, err = int64ToInt8(*s)
    94  			if *s < math.MinInt8 || *s > math.MaxInt8 {
    95  				err = errValueOutOfRange(*s)
    96  			} else {
    97  				val = int8(*s)
    98  			}
    99  		}
   100  	case *int:
   101  		if wasNil = s == nil; !wasNil {
   102  			val, err = intToInt8(*s)
   103  		}
   104  	case *int32:
   105  		if wasNil = s == nil; !wasNil {
   106  			val, err = int32ToInt8(*s)
   107  		}
   108  	case *int16:
   109  		if wasNil = s == nil; !wasNil {
   110  			val, err = int16ToInt8(*s)
   111  		}
   112  	case *int8:
   113  		if wasNil = s == nil; !wasNil {
   114  			val = *s
   115  		}
   116  	case *uint64:
   117  		if wasNil = s == nil; !wasNil {
   118  			val, err = uint64ToInt8(*s)
   119  		}
   120  	case *uint:
   121  		if wasNil = s == nil; !wasNil {
   122  			val, err = uintToInt8(*s)
   123  		}
   124  	case *uint32:
   125  		if wasNil = s == nil; !wasNil {
   126  			val, err = uint32ToInt8(*s)
   127  		}
   128  	case *uint16:
   129  		if wasNil = s == nil; !wasNil {
   130  			val, err = uint16ToInt8(*s)
   131  		}
   132  	case *uint8:
   133  		if wasNil = s == nil; !wasNil {
   134  			val, err = uint8ToInt8(*s)
   135  		}
   136  	case *string:
   137  		if wasNil = s == nil; !wasNil {
   138  			val, err = stringToInt8(*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 convertFromInt8(val int8, 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 = int64(val)
   168  		}
   169  	case *int:
   170  		if d == nil {
   171  			err = ErrNilDestination
   172  		} else if wasNull {
   173  			*d = 0
   174  		} else {
   175  			*d = int(val)
   176  		}
   177  	case *int32:
   178  		if d == nil {
   179  			err = ErrNilDestination
   180  		} else if wasNull {
   181  			*d = 0
   182  		} else {
   183  			*d = int32(val)
   184  		}
   185  	case *int16:
   186  		if d == nil {
   187  			err = ErrNilDestination
   188  		} else if wasNull {
   189  			*d = 0
   190  		} else {
   191  			*d = int16(val)
   192  		}
   193  	case *int8:
   194  		if d == nil {
   195  			err = ErrNilDestination
   196  		} else if wasNull {
   197  			*d = 0
   198  		} else {
   199  			*d = val
   200  		}
   201  	case *uint64:
   202  		if d == nil {
   203  			err = ErrNilDestination
   204  		} else if wasNull {
   205  			*d = 0
   206  		} else {
   207  			*d, err = int8ToUint64(val)
   208  		}
   209  	case *uint:
   210  		if d == nil {
   211  			err = ErrNilDestination
   212  		} else if wasNull {
   213  			*d = 0
   214  		} else {
   215  			*d, err = int8ToUint(val)
   216  		}
   217  	case *uint32:
   218  		if d == nil {
   219  			err = ErrNilDestination
   220  		} else if wasNull {
   221  			*d = 0
   222  		} else {
   223  			*d, err = int8ToUint32(val)
   224  		}
   225  	case *uint16:
   226  		if d == nil {
   227  			err = ErrNilDestination
   228  		} else if wasNull {
   229  			*d = 0
   230  		} else {
   231  			*d, err = int8ToUint16(val)
   232  		}
   233  	case *uint8:
   234  		if d == nil {
   235  			err = ErrNilDestination
   236  		} else if wasNull {
   237  			*d = 0
   238  		} else {
   239  			*d, err = int8ToUint8(val)
   240  		}
   241  	case *string:
   242  		if d == nil {
   243  			err = ErrNilDestination
   244  		} else if wasNull {
   245  			*d = ""
   246  		} else {
   247  			*d = strconv.FormatInt(int64(val), 10)
   248  		}
   249  	default:
   250  		err = errDestinationInvalid(dest)
   251  	}
   252  	if err != nil {
   253  		err = errDestinationConversionFailed(val, dest, err)
   254  	}
   255  	return
   256  }
   257  
   258  func writeInt8(val int8) (dest []byte) {
   259  	return []byte{byte(val)}
   260  }
   261  
   262  func readInt8(source []byte) (val int8, wasNull bool, err error) {
   263  	length := len(source)
   264  	if length == 0 {
   265  		wasNull = true
   266  	} else if length != primitive.LengthOfByte {
   267  		err = errWrongFixedLength(primitive.LengthOfByte, length)
   268  	} else {
   269  		val = int8(source[0])
   270  	}
   271  	if err != nil {
   272  		err = errCannotRead(val, err)
   273  	}
   274  	return
   275  }