github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/datacodec/blob.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  	"github.com/datastax/go-cassandra-native-protocol/datatype"
    19  	"github.com/datastax/go-cassandra-native-protocol/primitive"
    20  )
    21  
    22  // Blob is a codec for the CQL blob type. Its preferred Go type is []byte, but it can encode from and decode to
    23  // string as well. When given a []byte source or destination, the encoding and decoding operations are actually no-ops,
    24  // that is: the []byte value is passed along as is.
    25  var Blob Codec = &blobCodec{dataType: datatype.Blob}
    26  
    27  // PassThrough is another name for the Blob codec.
    28  var PassThrough = Blob
    29  
    30  // NewCustom returns a codec for the CQL custom type. Its preferred Go type is []byte, but it can encode from and decode
    31  // to string as well. This codec is identical to the Blob codec.
    32  func NewCustom(customType *datatype.Custom) Codec {
    33  	return &blobCodec{dataType: customType}
    34  }
    35  
    36  type blobCodec struct {
    37  	dataType datatype.DataType
    38  }
    39  
    40  func (c *blobCodec) DataType() datatype.DataType {
    41  	return c.dataType
    42  }
    43  
    44  func (c *blobCodec) Encode(source interface{}, version primitive.ProtocolVersion) (dest []byte, err error) {
    45  	if dest, err = convertToBytes(source); err != nil {
    46  		err = errCannotEncode(source, c.DataType(), version, err)
    47  	}
    48  	return
    49  }
    50  
    51  func (c *blobCodec) Decode(source []byte, dest interface{}, version primitive.ProtocolVersion) (wasNull bool, err error) {
    52  	if wasNull, err = convertFromBytes(source, dest); err != nil {
    53  		err = errCannotDecode(dest, c.DataType(), version, err)
    54  	}
    55  	return
    56  }
    57  
    58  func convertToBytes(source interface{}) (val []byte, err error) {
    59  	switch s := source.(type) {
    60  	case string:
    61  		val = []byte(s)
    62  	case []byte:
    63  		val = s
    64  	case *string:
    65  		if s != nil {
    66  			val = []byte(*s)
    67  		}
    68  	case *[]byte:
    69  		if s != nil {
    70  			val = *s
    71  		}
    72  	case nil:
    73  	default:
    74  		err = ErrConversionNotSupported
    75  	}
    76  	if err != nil {
    77  		err = errSourceConversionFailed(source, val, err)
    78  	}
    79  	return
    80  }
    81  
    82  func convertFromBytes(val []byte, dest interface{}) (wasNull bool, err error) {
    83  	wasNull = val == nil
    84  	switch d := dest.(type) {
    85  	case *interface{}:
    86  		if d == nil {
    87  			err = ErrNilDestination
    88  		} else if wasNull {
    89  			*d = nil
    90  		} else {
    91  			*d = val
    92  		}
    93  	case *string:
    94  		if d == nil {
    95  			err = ErrNilDestination
    96  		} else if wasNull {
    97  			*d = ""
    98  		} else {
    99  			*d = string(val)
   100  		}
   101  	case *[]byte:
   102  		if d == nil {
   103  			err = ErrNilDestination
   104  		} else if wasNull {
   105  			*d = nil
   106  		} else {
   107  			*d = val
   108  		}
   109  	default:
   110  		err = errDestinationInvalid(dest)
   111  	}
   112  	if err != nil {
   113  		err = errDestinationConversionFailed(val, dest, err)
   114  	}
   115  	return
   116  }