github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/datacodec/varchar.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  // Varchar is a codec for the CQL varchar (or text) type. Its preferred Go type is string, but it can encode
    23  // from and decode to []byte and []rune as well.
    24  var Varchar Codec = &stringCodec{datatype.Varchar}
    25  
    26  // Ascii is a codec for the CQL ascii type. Its preferred Go type is string, but it can encode from
    27  // and decode to []byte and []rune as well.
    28  // The returned codec does not actually enforce that all strings are valid ASCII; it's the caller's responsibility to
    29  // ensure that they are valid.
    30  var Ascii Codec = &stringCodec{datatype.Ascii}
    31  
    32  type stringCodec struct {
    33  	dataType datatype.DataType
    34  }
    35  
    36  func (c *stringCodec) DataType() datatype.DataType {
    37  	return c.dataType
    38  }
    39  
    40  func (c *stringCodec) Encode(source interface{}, version primitive.ProtocolVersion) (dest []byte, err error) {
    41  	if dest, err = convertToStringBytes(source); err != nil {
    42  		err = errCannotEncode(source, c.DataType(), version, err)
    43  	}
    44  	return
    45  }
    46  
    47  func (c *stringCodec) Decode(source []byte, dest interface{}, version primitive.ProtocolVersion) (wasNull bool, err error) {
    48  	if wasNull, err = convertFromStringBytes(source, dest); err != nil {
    49  		err = errCannotDecode(dest, c.DataType(), version, err)
    50  	}
    51  	return
    52  }
    53  
    54  func convertToStringBytes(source interface{}) (val []byte, err error) {
    55  	switch s := source.(type) {
    56  	case string:
    57  		val = []byte(s)
    58  	case []byte:
    59  		val = s
    60  	case []rune:
    61  		val = []byte(string(s))
    62  	case *string:
    63  		if s != nil {
    64  			val = []byte(*s)
    65  		}
    66  	case *[]byte:
    67  		if s != nil {
    68  			val = *s
    69  		}
    70  	case *[]rune:
    71  		if s != nil {
    72  			val = []byte(string(*s))
    73  		}
    74  	case nil:
    75  	default:
    76  		err = ErrConversionNotSupported
    77  	}
    78  	if err != nil {
    79  		err = errSourceConversionFailed(source, val, err)
    80  	}
    81  	return
    82  }
    83  
    84  func convertFromStringBytes(val []byte, dest interface{}) (wasNull bool, err error) {
    85  	wasNull = val == nil
    86  	switch d := dest.(type) {
    87  	case *interface{}:
    88  		if d == nil {
    89  			err = ErrNilDestination
    90  		} else if wasNull {
    91  			*d = nil
    92  		} else {
    93  			*d = string(val)
    94  		}
    95  	case *string:
    96  		if d == nil {
    97  			err = ErrNilDestination
    98  		} else if wasNull {
    99  			*d = ""
   100  		} else {
   101  			*d = string(val)
   102  		}
   103  	case *[]byte:
   104  		if d == nil {
   105  			err = ErrNilDestination
   106  		} else if wasNull {
   107  			*d = nil
   108  		} else {
   109  			*d = val
   110  		}
   111  	case *[]rune:
   112  		if d == nil {
   113  			err = ErrNilDestination
   114  		} else if wasNull {
   115  			*d = nil
   116  		} else {
   117  			*d = []rune(string(val))
   118  		}
   119  	default:
   120  		err = errDestinationInvalid(dest)
   121  	}
   122  	if err != nil {
   123  		err = errDestinationConversionFailed(val, dest, err)
   124  	}
   125  	return
   126  }