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 }