marshal.go (2,446 lines of code) (raw):
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40
* Copyright (c) 2012, The Gocql authors,
* provided under the BSD-3-Clause License.
* See the NOTICE file distributed with this work for additional information.
*/
package gocql
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"math"
"math/big"
"math/bits"
"net"
"reflect"
"strconv"
"strings"
"time"
"gopkg.in/inf.v0"
)
var (
bigOne = big.NewInt(1)
emptyValue reflect.Value
)
var (
ErrorUDTUnavailable = errors.New("UDT are not available on protocols less than 3, please update config")
)
// Marshaler is the interface implemented by objects that can marshal
// themselves into values understood by Cassandra.
type Marshaler interface {
MarshalCQL(info TypeInfo) ([]byte, error)
}
// Unmarshaler is the interface implemented by objects that can unmarshal
// a Cassandra specific description of themselves.
type Unmarshaler interface {
UnmarshalCQL(info TypeInfo, data []byte) error
}
// Marshal returns the CQL encoding of the value for the Cassandra
// internal type described by the info parameter.
//
// nil is serialized as CQL null.
// If value implements Marshaler, its MarshalCQL method is called to marshal the data.
// If value is a pointer, the pointed-to value is marshaled.
//
// Supported conversions are as follows, other type combinations may be added in the future:
//
// CQL type | Go type (value) | Note
// varchar, ascii, blob, text | string, []byte |
// boolean | bool |
// tinyint, smallint, int | integer types |
// tinyint, smallint, int | string | formatted as base 10 number
// bigint, counter | integer types |
// bigint, counter | big.Int | according to cassandra bigint specification the big.Int value limited to int64 size(an eight-byte two's complement integer.)
// bigint, counter | string | formatted as base 10 number
// float | float32 |
// double | float64 |
// decimal | inf.Dec |
// time | int64 | nanoseconds since start of day
// time | time.Duration | duration since start of day
// timestamp | int64 | milliseconds since Unix epoch
// timestamp | time.Time |
// list, set | slice, array |
// list, set | map[X]struct{} |
// map | map[X]Y |
// uuid, timeuuid | gocql.UUID |
// uuid, timeuuid | [16]byte | raw UUID bytes
// uuid, timeuuid | []byte | raw UUID bytes, length must be 16 bytes
// uuid, timeuuid | string | hex representation, see ParseUUID
// varint | integer types |
// varint | big.Int |
// varint | string | value of number in decimal notation
// inet | net.IP |
// inet | string | IPv4 or IPv6 address string
// tuple | slice, array |
// tuple | struct | fields are marshaled in order of declaration
// user-defined type | gocql.UDTMarshaler | MarshalUDT is called
// user-defined type | map[string]interface{} |
// user-defined type | struct | struct fields' cql tags are used for column names
// date | int64 | milliseconds since Unix epoch to start of day (in UTC)
// date | time.Time | start of day (in UTC)
// date | string | parsed using "2006-01-02" format
// duration | int64 | duration in nanoseconds
// duration | time.Duration |
// duration | gocql.Duration |
// duration | string | parsed with time.ParseDuration
//
// The marshal/unmarshal error provides a list of supported types when an unsupported type is attempted.
func Marshal(info TypeInfo, value interface{}) ([]byte, error) {
if info.Version() < protoVersion1 {
panic("protocol version not set")
}
if valueRef := reflect.ValueOf(value); valueRef.Kind() == reflect.Ptr {
if valueRef.IsNil() {
return nil, nil
} else if v, ok := value.(Marshaler); ok {
return v.MarshalCQL(info)
} else {
return Marshal(info, valueRef.Elem().Interface())
}
}
if v, ok := value.(Marshaler); ok {
return v.MarshalCQL(info)
}
switch info.Type() {
case TypeVarchar, TypeAscii, TypeBlob, TypeText:
return marshalVarchar(info, value)
case TypeBoolean:
return marshalBool(info, value)
case TypeTinyInt:
return marshalTinyInt(info, value)
case TypeSmallInt:
return marshalSmallInt(info, value)
case TypeInt:
return marshalInt(info, value)
case TypeBigInt, TypeCounter:
return marshalBigInt(info, value)
case TypeFloat:
return marshalFloat(info, value)
case TypeDouble:
return marshalDouble(info, value)
case TypeDecimal:
return marshalDecimal(info, value)
case TypeTime:
return marshalTime(info, value)
case TypeTimestamp:
return marshalTimestamp(info, value)
case TypeList, TypeSet:
return marshalList(info, value)
case TypeMap:
return marshalMap(info, value)
case TypeUUID, TypeTimeUUID:
return marshalUUID(info, value)
case TypeVarint:
return marshalVarint(info, value)
case TypeInet:
return marshalInet(info, value)
case TypeTuple:
return marshalTuple(info, value)
case TypeUDT:
return marshalUDT(info, value)
case TypeDate:
return marshalDate(info, value)
case TypeDuration:
return marshalDuration(info, value)
case TypeCustom:
if vector, ok := info.(VectorType); ok {
return marshalVector(vector, value)
}
}
// detect protocol 2 UDT
if strings.HasPrefix(info.Custom(), "org.apache.cassandra.db.marshal.UserType") && info.Version() < 3 {
return nil, ErrorUDTUnavailable
}
// TODO(tux21b): add the remaining types
return nil, fmt.Errorf("can not marshal %T into %s", value, info)
}
// Unmarshal parses the CQL encoded data based on the info parameter that
// describes the Cassandra internal data type and stores the result in the
// value pointed by value.
//
// If value implements Unmarshaler, it's UnmarshalCQL method is called to
// unmarshal the data.
// If value is a pointer to pointer, it is set to nil if the CQL value is
// null. Otherwise, nulls are unmarshalled as zero value.
//
// Supported conversions are as follows, other type combinations may be added in the future:
//
// CQL type | Go type (value) | Note
// varchar, ascii, blob, text | *string |
// varchar, ascii, blob, text | *[]byte | non-nil buffer is reused
// bool | *bool |
// tinyint, smallint, int, bigint, counter | *integer types |
// tinyint, smallint, int, bigint, counter | *big.Int |
// tinyint, smallint, int, bigint, counter | *string | formatted as base 10 number
// float | *float32 |
// double | *float64 |
// decimal | *inf.Dec |
// time | *int64 | nanoseconds since start of day
// time | *time.Duration |
// timestamp | *int64 | milliseconds since Unix epoch
// timestamp | *time.Time |
// list, set | *slice, *array |
// map | *map[X]Y |
// uuid, timeuuid | *string | see UUID.String
// uuid, timeuuid | *[]byte | raw UUID bytes
// uuid, timeuuid | *gocql.UUID |
// timeuuid | *time.Time | timestamp of the UUID
// inet | *net.IP |
// inet | *string | IPv4 or IPv6 address string
// tuple | *slice, *array |
// tuple | *struct | struct fields are set in order of declaration
// user-defined types | gocql.UDTUnmarshaler | UnmarshalUDT is called
// user-defined types | *map[string]interface{} |
// user-defined types | *struct | cql tag is used to determine field name
// date | *time.Time | time of beginning of the day (in UTC)
// date | *string | formatted with 2006-01-02 format
// duration | *gocql.Duration |
func Unmarshal(info TypeInfo, data []byte, value interface{}) error {
if v, ok := value.(Unmarshaler); ok {
return v.UnmarshalCQL(info, data)
}
if isNullableValue(value) {
return unmarshalNullable(info, data, value)
}
switch info.Type() {
case TypeVarchar, TypeAscii, TypeBlob, TypeText:
return unmarshalVarchar(info, data, value)
case TypeBoolean:
return unmarshalBool(info, data, value)
case TypeInt:
return unmarshalInt(info, data, value)
case TypeBigInt, TypeCounter:
return unmarshalBigInt(info, data, value)
case TypeVarint:
return unmarshalVarint(info, data, value)
case TypeSmallInt:
return unmarshalSmallInt(info, data, value)
case TypeTinyInt:
return unmarshalTinyInt(info, data, value)
case TypeFloat:
return unmarshalFloat(info, data, value)
case TypeDouble:
return unmarshalDouble(info, data, value)
case TypeDecimal:
return unmarshalDecimal(info, data, value)
case TypeTime:
return unmarshalTime(info, data, value)
case TypeTimestamp:
return unmarshalTimestamp(info, data, value)
case TypeList, TypeSet:
return unmarshalList(info, data, value)
case TypeMap:
return unmarshalMap(info, data, value)
case TypeTimeUUID:
return unmarshalTimeUUID(info, data, value)
case TypeUUID:
return unmarshalUUID(info, data, value)
case TypeInet:
return unmarshalInet(info, data, value)
case TypeTuple:
return unmarshalTuple(info, data, value)
case TypeUDT:
return unmarshalUDT(info, data, value)
case TypeDate:
return unmarshalDate(info, data, value)
case TypeDuration:
return unmarshalDuration(info, data, value)
case TypeCustom:
if vector, ok := info.(VectorType); ok {
return unmarshalVector(vector, data, value)
}
}
// detect protocol 2 UDT
if strings.HasPrefix(info.Custom(), "org.apache.cassandra.db.marshal.UserType") && info.Version() < 3 {
return ErrorUDTUnavailable
}
// TODO(tux21b): add the remaining types
return fmt.Errorf("can not unmarshal %s into %T", info, value)
}
func isNullableValue(value interface{}) bool {
v := reflect.ValueOf(value)
return v.Kind() == reflect.Ptr && v.Type().Elem().Kind() == reflect.Ptr
}
func isNullData(info TypeInfo, data []byte) bool {
return data == nil
}
func unmarshalNullable(info TypeInfo, data []byte, value interface{}) error {
valueRef := reflect.ValueOf(value)
if isNullData(info, data) {
nilValue := reflect.Zero(valueRef.Type().Elem())
valueRef.Elem().Set(nilValue)
return nil
}
newValue := reflect.New(valueRef.Type().Elem().Elem())
valueRef.Elem().Set(newValue)
return Unmarshal(info, data, newValue.Interface())
}
func marshalVarchar(info TypeInfo, value interface{}) ([]byte, error) {
switch v := value.(type) {
case Marshaler:
return v.MarshalCQL(info)
case unsetColumn:
return nil, nil
case string:
return []byte(v), nil
case []byte:
return v, nil
}
if value == nil {
return nil, nil
}
rv := reflect.ValueOf(value)
t := rv.Type()
k := t.Kind()
switch {
case k == reflect.String:
return []byte(rv.String()), nil
case k == reflect.Slice && t.Elem().Kind() == reflect.Uint8:
return rv.Bytes(), nil
}
return nil, marshalErrorf("can not marshal %T into %s. Accepted types: Marshaler, string, []byte, UnsetValue.", value, info)
}
func unmarshalVarchar(info TypeInfo, data []byte, value interface{}) error {
switch v := value.(type) {
case Unmarshaler:
return v.UnmarshalCQL(info, data)
case *string:
*v = string(data)
return nil
case *[]byte:
if data != nil {
*v = append((*v)[:0], data...)
} else {
*v = nil
}
return nil
}
rv := reflect.ValueOf(value)
if rv.Kind() != reflect.Ptr {
return unmarshalErrorf("can not unmarshal into non-pointer %T", value)
}
rv = rv.Elem()
t := rv.Type()
k := t.Kind()
switch {
case k == reflect.String:
rv.SetString(string(data))
return nil
case k == reflect.Slice && t.Elem().Kind() == reflect.Uint8:
var dataCopy []byte
if data != nil {
dataCopy = make([]byte, len(data))
copy(dataCopy, data)
}
rv.SetBytes(dataCopy)
return nil
}
return unmarshalErrorf("can not unmarshal %s into %T. Accepted types: Unmarshaler, *string, *[]byte", info, value)
}
func marshalSmallInt(info TypeInfo, value interface{}) ([]byte, error) {
switch v := value.(type) {
case Marshaler:
return v.MarshalCQL(info)
case unsetColumn:
return nil, nil
case int16:
return encShort(v), nil
case uint16:
return encShort(int16(v)), nil
case int8:
return encShort(int16(v)), nil
case uint8:
return encShort(int16(v)), nil
case int:
if v > math.MaxInt16 || v < math.MinInt16 {
return nil, marshalErrorf("marshal smallint: value %d out of range", v)
}
return encShort(int16(v)), nil
case int32:
if v > math.MaxInt16 || v < math.MinInt16 {
return nil, marshalErrorf("marshal smallint: value %d out of range", v)
}
return encShort(int16(v)), nil
case int64:
if v > math.MaxInt16 || v < math.MinInt16 {
return nil, marshalErrorf("marshal smallint: value %d out of range", v)
}
return encShort(int16(v)), nil
case uint:
if v > math.MaxUint16 {
return nil, marshalErrorf("marshal smallint: value %d out of range", v)
}
return encShort(int16(v)), nil
case uint32:
if v > math.MaxUint16 {
return nil, marshalErrorf("marshal smallint: value %d out of range", v)
}
return encShort(int16(v)), nil
case uint64:
if v > math.MaxUint16 {
return nil, marshalErrorf("marshal smallint: value %d out of range", v)
}
return encShort(int16(v)), nil
case string:
n, err := strconv.ParseInt(v, 10, 16)
if err != nil {
return nil, marshalErrorf("can not marshal %T into %s: %v", value, info, err)
}
return encShort(int16(n)), nil
}
if value == nil {
return nil, nil
}
switch rv := reflect.ValueOf(value); rv.Type().Kind() {
case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
v := rv.Int()
if v > math.MaxInt16 || v < math.MinInt16 {
return nil, marshalErrorf("marshal smallint: value %d out of range", v)
}
return encShort(int16(v)), nil
case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8:
v := rv.Uint()
if v > math.MaxUint16 {
return nil, marshalErrorf("marshal smallint: value %d out of range", v)
}
return encShort(int16(v)), nil
case reflect.Ptr:
if rv.IsNil() {
return nil, nil
}
}
return nil, marshalErrorf("can not marshal %T into %s. Accepted types: Marshaler, int16, uint16, int8, uint8, int, uint, int32, uint32, int64, uint64, string, UnsetValue.", value, info)
}
func marshalTinyInt(info TypeInfo, value interface{}) ([]byte, error) {
switch v := value.(type) {
case Marshaler:
return v.MarshalCQL(info)
case unsetColumn:
return nil, nil
case int8:
return []byte{byte(v)}, nil
case uint8:
return []byte{byte(v)}, nil
case int16:
if v > math.MaxInt8 || v < math.MinInt8 {
return nil, marshalErrorf("marshal tinyint: value %d out of range", v)
}
return []byte{byte(v)}, nil
case uint16:
if v > math.MaxUint8 {
return nil, marshalErrorf("marshal tinyint: value %d out of range", v)
}
return []byte{byte(v)}, nil
case int:
if v > math.MaxInt8 || v < math.MinInt8 {
return nil, marshalErrorf("marshal tinyint: value %d out of range", v)
}
return []byte{byte(v)}, nil
case int32:
if v > math.MaxInt8 || v < math.MinInt8 {
return nil, marshalErrorf("marshal tinyint: value %d out of range", v)
}
return []byte{byte(v)}, nil
case int64:
if v > math.MaxInt8 || v < math.MinInt8 {
return nil, marshalErrorf("marshal tinyint: value %d out of range", v)
}
return []byte{byte(v)}, nil
case uint:
if v > math.MaxUint8 {
return nil, marshalErrorf("marshal tinyint: value %d out of range", v)
}
return []byte{byte(v)}, nil
case uint32:
if v > math.MaxUint8 {
return nil, marshalErrorf("marshal tinyint: value %d out of range", v)
}
return []byte{byte(v)}, nil
case uint64:
if v > math.MaxUint8 {
return nil, marshalErrorf("marshal tinyint: value %d out of range", v)
}
return []byte{byte(v)}, nil
case string:
n, err := strconv.ParseInt(v, 10, 8)
if err != nil {
return nil, marshalErrorf("can not marshal %T into %s: %v", value, info, err)
}
return []byte{byte(n)}, nil
}
if value == nil {
return nil, nil
}
switch rv := reflect.ValueOf(value); rv.Type().Kind() {
case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
v := rv.Int()
if v > math.MaxInt8 || v < math.MinInt8 {
return nil, marshalErrorf("marshal tinyint: value %d out of range", v)
}
return []byte{byte(v)}, nil
case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8:
v := rv.Uint()
if v > math.MaxUint8 {
return nil, marshalErrorf("marshal tinyint: value %d out of range", v)
}
return []byte{byte(v)}, nil
case reflect.Ptr:
if rv.IsNil() {
return nil, nil
}
}
return nil, marshalErrorf("can not marshal %T into %s. Accepted types: Marshaler, int8, uint8, int16, uint16, int, uint, int32, uint32, int64, uint64, string, UnsetValue.", value, info)
}
func marshalInt(info TypeInfo, value interface{}) ([]byte, error) {
switch v := value.(type) {
case Marshaler:
return v.MarshalCQL(info)
case unsetColumn:
return nil, nil
case int:
if v > math.MaxInt32 || v < math.MinInt32 {
return nil, marshalErrorf("marshal int: value %d out of range", v)
}
return encInt(int32(v)), nil
case uint:
if v > math.MaxUint32 {
return nil, marshalErrorf("marshal int: value %d out of range", v)
}
return encInt(int32(v)), nil
case int64:
if v > math.MaxInt32 || v < math.MinInt32 {
return nil, marshalErrorf("marshal int: value %d out of range", v)
}
return encInt(int32(v)), nil
case uint64:
if v > math.MaxUint32 {
return nil, marshalErrorf("marshal int: value %d out of range", v)
}
return encInt(int32(v)), nil
case int32:
return encInt(v), nil
case uint32:
return encInt(int32(v)), nil
case int16:
return encInt(int32(v)), nil
case uint16:
return encInt(int32(v)), nil
case int8:
return encInt(int32(v)), nil
case uint8:
return encInt(int32(v)), nil
case string:
i, err := strconv.ParseInt(v, 10, 32)
if err != nil {
return nil, marshalErrorf("can not marshal string to int: %s", err)
}
return encInt(int32(i)), nil
}
if value == nil {
return nil, nil
}
switch rv := reflect.ValueOf(value); rv.Type().Kind() {
case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
v := rv.Int()
if v > math.MaxInt32 || v < math.MinInt32 {
return nil, marshalErrorf("marshal int: value %d out of range", v)
}
return encInt(int32(v)), nil
case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8:
v := rv.Uint()
if v > math.MaxInt32 {
return nil, marshalErrorf("marshal int: value %d out of range", v)
}
return encInt(int32(v)), nil
case reflect.Ptr:
if rv.IsNil() {
return nil, nil
}
}
return nil, marshalErrorf("can not marshal %T into %s. Accepted types: Marshaler, int8, uint8, int16, uint16, int, uint, int32, uint32, int64, uint64, string, UnsetValue.", value, info)
}
func encInt(x int32) []byte {
return []byte{byte(x >> 24), byte(x >> 16), byte(x >> 8), byte(x)}
}
func decInt(x []byte) int32 {
if len(x) != 4 {
return 0
}
return int32(x[0])<<24 | int32(x[1])<<16 | int32(x[2])<<8 | int32(x[3])
}
func encShort(x int16) []byte {
p := make([]byte, 2)
p[0] = byte(x >> 8)
p[1] = byte(x)
return p
}
func decShort(p []byte) int16 {
if len(p) != 2 {
return 0
}
return int16(p[0])<<8 | int16(p[1])
}
func decTiny(p []byte) int8 {
if len(p) != 1 {
return 0
}
return int8(p[0])
}
func marshalBigInt(info TypeInfo, value interface{}) ([]byte, error) {
switch v := value.(type) {
case Marshaler:
return v.MarshalCQL(info)
case unsetColumn:
return nil, nil
case int:
return encBigInt(int64(v)), nil
case uint:
if uint64(v) > math.MaxInt64 {
return nil, marshalErrorf("marshal bigint: value %d out of range", v)
}
return encBigInt(int64(v)), nil
case int64:
return encBigInt(v), nil
case uint64:
return encBigInt(int64(v)), nil
case int32:
return encBigInt(int64(v)), nil
case uint32:
return encBigInt(int64(v)), nil
case int16:
return encBigInt(int64(v)), nil
case uint16:
return encBigInt(int64(v)), nil
case int8:
return encBigInt(int64(v)), nil
case uint8:
return encBigInt(int64(v)), nil
case big.Int:
if !v.IsInt64() {
return nil, marshalErrorf("marshal bigint: value %v out of range", &v)
}
return encBigInt(v.Int64()), nil
case string:
i, err := strconv.ParseInt(value.(string), 10, 64)
if err != nil {
return nil, marshalErrorf("can not marshal string to bigint: %s", err)
}
return encBigInt(i), nil
}
if value == nil {
return nil, nil
}
rv := reflect.ValueOf(value)
switch rv.Type().Kind() {
case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
v := rv.Int()
return encBigInt(v), nil
case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8:
v := rv.Uint()
if v > math.MaxInt64 {
return nil, marshalErrorf("marshal bigint: value %d out of range", v)
}
return encBigInt(int64(v)), nil
}
return nil, marshalErrorf("can not marshal %T into %s. Accepted types: big.Int, Marshaler, int8, uint8, int16, uint16, int, uint, int32, uint32, int64, uint64, string, UnsetValue.", value, info)
}
func encBigInt(x int64) []byte {
return []byte{byte(x >> 56), byte(x >> 48), byte(x >> 40), byte(x >> 32),
byte(x >> 24), byte(x >> 16), byte(x >> 8), byte(x)}
}
func bytesToInt64(data []byte) (ret int64) {
for i := range data {
ret |= int64(data[i]) << (8 * uint(len(data)-i-1))
}
return ret
}
func bytesToUint64(data []byte) (ret uint64) {
for i := range data {
ret |= uint64(data[i]) << (8 * uint(len(data)-i-1))
}
return ret
}
func unmarshalBigInt(info TypeInfo, data []byte, value interface{}) error {
return unmarshalIntlike(info, decBigInt(data), data, value)
}
func unmarshalInt(info TypeInfo, data []byte, value interface{}) error {
return unmarshalIntlike(info, int64(decInt(data)), data, value)
}
func unmarshalSmallInt(info TypeInfo, data []byte, value interface{}) error {
return unmarshalIntlike(info, int64(decShort(data)), data, value)
}
func unmarshalTinyInt(info TypeInfo, data []byte, value interface{}) error {
return unmarshalIntlike(info, int64(decTiny(data)), data, value)
}
func unmarshalVarint(info TypeInfo, data []byte, value interface{}) error {
switch v := value.(type) {
case *big.Int:
return unmarshalIntlike(info, 0, data, value)
case *uint64:
if len(data) == 9 && data[0] == 0 {
*v = bytesToUint64(data[1:])
return nil
}
}
if len(data) > 8 {
return unmarshalErrorf("unmarshal int: varint value %v out of range for %T (use big.Int)", data, value)
}
int64Val := bytesToInt64(data)
if len(data) > 0 && len(data) < 8 && data[0]&0x80 > 0 {
int64Val -= (1 << uint(len(data)*8))
}
return unmarshalIntlike(info, int64Val, data, value)
}
func marshalVarint(info TypeInfo, value interface{}) ([]byte, error) {
var (
retBytes []byte
err error
)
switch v := value.(type) {
case unsetColumn:
return nil, nil
case uint64:
if v > uint64(math.MaxInt64) {
retBytes = make([]byte, 9)
binary.BigEndian.PutUint64(retBytes[1:], v)
} else {
retBytes = make([]byte, 8)
binary.BigEndian.PutUint64(retBytes, v)
}
case big.Int:
retBytes = encBigInt2C(&v)
default:
retBytes, err = marshalBigInt(info, value)
}
if err == nil {
// trim down to most significant byte
i := 0
for ; i < len(retBytes)-1; i++ {
b0 := retBytes[i]
if b0 != 0 && b0 != 0xFF {
break
}
b1 := retBytes[i+1]
if b0 == 0 && b1 != 0 {
if b1&0x80 == 0 {
i++
}
break
}
if b0 == 0xFF && b1 != 0xFF {
if b1&0x80 > 0 {
i++
}
break
}
}
retBytes = retBytes[i:]
}
return retBytes, err
}
func unmarshalIntlike(info TypeInfo, int64Val int64, data []byte, value interface{}) error {
switch v := value.(type) {
case *int:
if ^uint(0) == math.MaxUint32 && (int64Val < math.MinInt32 || int64Val > math.MaxInt32) {
return unmarshalErrorf("unmarshal int: value %d out of range for %T", int64Val, *v)
}
*v = int(int64Val)
return nil
case *uint:
unitVal := uint64(int64Val)
switch info.Type() {
case TypeInt:
*v = uint(unitVal) & 0xFFFFFFFF
case TypeSmallInt:
*v = uint(unitVal) & 0xFFFF
case TypeTinyInt:
*v = uint(unitVal) & 0xFF
default:
if ^uint(0) == math.MaxUint32 && (int64Val < 0 || int64Val > math.MaxUint32) {
return unmarshalErrorf("unmarshal int: value %d out of range for %T", unitVal, *v)
}
*v = uint(unitVal)
}
return nil
case *int64:
*v = int64Val
return nil
case *uint64:
switch info.Type() {
case TypeInt:
*v = uint64(int64Val) & 0xFFFFFFFF
case TypeSmallInt:
*v = uint64(int64Val) & 0xFFFF
case TypeTinyInt:
*v = uint64(int64Val) & 0xFF
default:
*v = uint64(int64Val)
}
return nil
case *int32:
if int64Val < math.MinInt32 || int64Val > math.MaxInt32 {
return unmarshalErrorf("unmarshal int: value %d out of range for %T", int64Val, *v)
}
*v = int32(int64Val)
return nil
case *uint32:
switch info.Type() {
case TypeInt:
*v = uint32(int64Val) & 0xFFFFFFFF
case TypeSmallInt:
*v = uint32(int64Val) & 0xFFFF
case TypeTinyInt:
*v = uint32(int64Val) & 0xFF
default:
if int64Val < 0 || int64Val > math.MaxUint32 {
return unmarshalErrorf("unmarshal int: value %d out of range for %T", int64Val, *v)
}
*v = uint32(int64Val) & 0xFFFFFFFF
}
return nil
case *int16:
if int64Val < math.MinInt16 || int64Val > math.MaxInt16 {
return unmarshalErrorf("unmarshal int: value %d out of range for %T", int64Val, *v)
}
*v = int16(int64Val)
return nil
case *uint16:
switch info.Type() {
case TypeSmallInt:
*v = uint16(int64Val) & 0xFFFF
case TypeTinyInt:
*v = uint16(int64Val) & 0xFF
default:
if int64Val < 0 || int64Val > math.MaxUint16 {
return unmarshalErrorf("unmarshal int: value %d out of range for %T", int64Val, *v)
}
*v = uint16(int64Val) & 0xFFFF
}
return nil
case *int8:
if int64Val < math.MinInt8 || int64Val > math.MaxInt8 {
return unmarshalErrorf("unmarshal int: value %d out of range for %T", int64Val, *v)
}
*v = int8(int64Val)
return nil
case *uint8:
if info.Type() != TypeTinyInt && (int64Val < 0 || int64Val > math.MaxUint8) {
return unmarshalErrorf("unmarshal int: value %d out of range for %T", int64Val, *v)
}
*v = uint8(int64Val) & 0xFF
return nil
case *big.Int:
decBigInt2C(data, v)
return nil
case *string:
*v = strconv.FormatInt(int64Val, 10)
return nil
}
rv := reflect.ValueOf(value)
if rv.Kind() != reflect.Ptr {
return unmarshalErrorf("can not unmarshal into non-pointer %T", value)
}
rv = rv.Elem()
switch rv.Type().Kind() {
case reflect.Int:
if ^uint(0) == math.MaxUint32 && (int64Val < math.MinInt32 || int64Val > math.MaxInt32) {
return unmarshalErrorf("unmarshal int: value %d out of range", int64Val)
}
rv.SetInt(int64Val)
return nil
case reflect.Int64:
rv.SetInt(int64Val)
return nil
case reflect.Int32:
if int64Val < math.MinInt32 || int64Val > math.MaxInt32 {
return unmarshalErrorf("unmarshal int: value %d out of range", int64Val)
}
rv.SetInt(int64Val)
return nil
case reflect.Int16:
if int64Val < math.MinInt16 || int64Val > math.MaxInt16 {
return unmarshalErrorf("unmarshal int: value %d out of range", int64Val)
}
rv.SetInt(int64Val)
return nil
case reflect.Int8:
if int64Val < math.MinInt8 || int64Val > math.MaxInt8 {
return unmarshalErrorf("unmarshal int: value %d out of range", int64Val)
}
rv.SetInt(int64Val)
return nil
case reflect.Uint:
unitVal := uint64(int64Val)
switch info.Type() {
case TypeInt:
rv.SetUint(unitVal & 0xFFFFFFFF)
case TypeSmallInt:
rv.SetUint(unitVal & 0xFFFF)
case TypeTinyInt:
rv.SetUint(unitVal & 0xFF)
default:
if ^uint(0) == math.MaxUint32 && (int64Val < 0 || int64Val > math.MaxUint32) {
return unmarshalErrorf("unmarshal int: value %d out of range for %s", unitVal, rv.Type())
}
rv.SetUint(unitVal)
}
return nil
case reflect.Uint64:
unitVal := uint64(int64Val)
switch info.Type() {
case TypeInt:
rv.SetUint(unitVal & 0xFFFFFFFF)
case TypeSmallInt:
rv.SetUint(unitVal & 0xFFFF)
case TypeTinyInt:
rv.SetUint(unitVal & 0xFF)
default:
rv.SetUint(unitVal)
}
return nil
case reflect.Uint32:
unitVal := uint64(int64Val)
switch info.Type() {
case TypeInt:
rv.SetUint(unitVal & 0xFFFFFFFF)
case TypeSmallInt:
rv.SetUint(unitVal & 0xFFFF)
case TypeTinyInt:
rv.SetUint(unitVal & 0xFF)
default:
if int64Val < 0 || int64Val > math.MaxUint32 {
return unmarshalErrorf("unmarshal int: value %d out of range for %s", int64Val, rv.Type())
}
rv.SetUint(unitVal & 0xFFFFFFFF)
}
return nil
case reflect.Uint16:
unitVal := uint64(int64Val)
switch info.Type() {
case TypeSmallInt:
rv.SetUint(unitVal & 0xFFFF)
case TypeTinyInt:
rv.SetUint(unitVal & 0xFF)
default:
if int64Val < 0 || int64Val > math.MaxUint16 {
return unmarshalErrorf("unmarshal int: value %d out of range for %s", int64Val, rv.Type())
}
rv.SetUint(unitVal & 0xFFFF)
}
return nil
case reflect.Uint8:
if info.Type() != TypeTinyInt && (int64Val < 0 || int64Val > math.MaxUint8) {
return unmarshalErrorf("unmarshal int: value %d out of range for %s", int64Val, rv.Type())
}
rv.SetUint(uint64(int64Val) & 0xff)
return nil
}
return unmarshalErrorf("can not unmarshal %s into %T. Accepted types: big.Int, Marshaler, int8, uint8, int16, uint16, int, uint, int32, uint32, int64, uint64, string.", info, value)
}
func decBigInt(data []byte) int64 {
if len(data) != 8 {
return 0
}
return int64(data[0])<<56 | int64(data[1])<<48 |
int64(data[2])<<40 | int64(data[3])<<32 |
int64(data[4])<<24 | int64(data[5])<<16 |
int64(data[6])<<8 | int64(data[7])
}
func marshalBool(info TypeInfo, value interface{}) ([]byte, error) {
switch v := value.(type) {
case Marshaler:
return v.MarshalCQL(info)
case unsetColumn:
return nil, nil
case bool:
return encBool(v), nil
}
if value == nil {
return nil, nil
}
rv := reflect.ValueOf(value)
switch rv.Type().Kind() {
case reflect.Bool:
return encBool(rv.Bool()), nil
}
return nil, marshalErrorf("can not marshal %T into %s. Accepted types: Marshaler, bool, UnsetValue.", value, info)
}
func encBool(v bool) []byte {
if v {
return []byte{1}
}
return []byte{0}
}
func unmarshalBool(info TypeInfo, data []byte, value interface{}) error {
switch v := value.(type) {
case Unmarshaler:
return v.UnmarshalCQL(info, data)
case *bool:
*v = decBool(data)
return nil
}
rv := reflect.ValueOf(value)
if rv.Kind() != reflect.Ptr {
return unmarshalErrorf("can not unmarshal into non-pointer %T", value)
}
rv = rv.Elem()
switch rv.Type().Kind() {
case reflect.Bool:
rv.SetBool(decBool(data))
return nil
}
return unmarshalErrorf("can not unmarshal %s into %T. Accepted types: Unmarshaler, *bool.", info, value)
}
func decBool(v []byte) bool {
if len(v) == 0 {
return false
}
return v[0] != 0
}
func marshalFloat(info TypeInfo, value interface{}) ([]byte, error) {
switch v := value.(type) {
case Marshaler:
return v.MarshalCQL(info)
case unsetColumn:
return nil, nil
case float32:
return encInt(int32(math.Float32bits(v))), nil
}
if value == nil {
return nil, nil
}
rv := reflect.ValueOf(value)
switch rv.Type().Kind() {
case reflect.Float32:
return encInt(int32(math.Float32bits(float32(rv.Float())))), nil
}
return nil, marshalErrorf("can not marshal %T into %s. Accepted types: Marshaler, float32, UnsetValue.", value, info)
}
func unmarshalFloat(info TypeInfo, data []byte, value interface{}) error {
switch v := value.(type) {
case Unmarshaler:
return v.UnmarshalCQL(info, data)
case *float32:
*v = math.Float32frombits(uint32(decInt(data)))
return nil
}
rv := reflect.ValueOf(value)
if rv.Kind() != reflect.Ptr {
return unmarshalErrorf("can not unmarshal into non-pointer %T", value)
}
rv = rv.Elem()
switch rv.Type().Kind() {
case reflect.Float32:
rv.SetFloat(float64(math.Float32frombits(uint32(decInt(data)))))
return nil
}
return unmarshalErrorf("can not unmarshal %s into %T. Accepted types: Unmarshaler, *float32, UnsetValue.", info, value)
}
func marshalDouble(info TypeInfo, value interface{}) ([]byte, error) {
switch v := value.(type) {
case Marshaler:
return v.MarshalCQL(info)
case unsetColumn:
return nil, nil
case float64:
return encBigInt(int64(math.Float64bits(v))), nil
}
if value == nil {
return nil, nil
}
rv := reflect.ValueOf(value)
switch rv.Type().Kind() {
case reflect.Float64:
return encBigInt(int64(math.Float64bits(rv.Float()))), nil
}
return nil, marshalErrorf("can not marshal %T into %s. Accepted types: Marshaler, float64, UnsetValue.", value, info)
}
func unmarshalDouble(info TypeInfo, data []byte, value interface{}) error {
switch v := value.(type) {
case Unmarshaler:
return v.UnmarshalCQL(info, data)
case *float64:
*v = math.Float64frombits(uint64(decBigInt(data)))
return nil
}
rv := reflect.ValueOf(value)
if rv.Kind() != reflect.Ptr {
return unmarshalErrorf("can not unmarshal into non-pointer %T", value)
}
rv = rv.Elem()
switch rv.Type().Kind() {
case reflect.Float64:
rv.SetFloat(math.Float64frombits(uint64(decBigInt(data))))
return nil
}
return unmarshalErrorf("can not unmarshal %s into %T. Accepted types: Unmarshaler, *float64.", info, value)
}
func marshalDecimal(info TypeInfo, value interface{}) ([]byte, error) {
if value == nil {
return nil, nil
}
switch v := value.(type) {
case Marshaler:
return v.MarshalCQL(info)
case unsetColumn:
return nil, nil
case inf.Dec:
unscaled := encBigInt2C(v.UnscaledBig())
if unscaled == nil {
return nil, marshalErrorf("can not marshal %T into %s", value, info)
}
buf := make([]byte, 4+len(unscaled))
copy(buf[0:4], encInt(int32(v.Scale())))
copy(buf[4:], unscaled)
return buf, nil
}
return nil, marshalErrorf("can not marshal %T into %s. Accepted types: Marshaler, inf.Dec, UnsetValue.", value, info)
}
func unmarshalDecimal(info TypeInfo, data []byte, value interface{}) error {
switch v := value.(type) {
case Unmarshaler:
return v.UnmarshalCQL(info, data)
case *inf.Dec:
if len(data) < 4 {
return unmarshalErrorf("inf.Dec needs at least 4 bytes, while value has only %d", len(data))
}
scale := decInt(data[0:4])
unscaled := decBigInt2C(data[4:], nil)
*v = *inf.NewDecBig(unscaled, inf.Scale(scale))
return nil
}
return unmarshalErrorf("can not unmarshal %s into %T. Accepted types: Unmarshaler, *inf.Dec.", info, value)
}
// decBigInt2C sets the value of n to the big-endian two's complement
// value stored in the given data. If data[0]&80 != 0, the number
// is negative. If data is empty, the result will be 0.
func decBigInt2C(data []byte, n *big.Int) *big.Int {
if n == nil {
n = new(big.Int)
}
n.SetBytes(data)
if len(data) > 0 && data[0]&0x80 > 0 {
n.Sub(n, new(big.Int).Lsh(bigOne, uint(len(data))*8))
}
return n
}
// encBigInt2C returns the big-endian two's complement
// form of n.
func encBigInt2C(n *big.Int) []byte {
switch n.Sign() {
case 0:
return []byte{0}
case 1:
b := n.Bytes()
if b[0]&0x80 > 0 {
b = append([]byte{0}, b...)
}
return b
case -1:
length := uint(n.BitLen()/8+1) * 8
b := new(big.Int).Add(n, new(big.Int).Lsh(bigOne, length)).Bytes()
// When the most significant bit is on a byte
// boundary, we can get some extra significant
// bits, so strip them off when that happens.
if len(b) >= 2 && b[0] == 0xff && b[1]&0x80 != 0 {
b = b[1:]
}
return b
}
return nil
}
func marshalTime(info TypeInfo, value interface{}) ([]byte, error) {
switch v := value.(type) {
case Marshaler:
return v.MarshalCQL(info)
case unsetColumn:
return nil, nil
case int64:
return encBigInt(v), nil
case time.Duration:
return encBigInt(v.Nanoseconds()), nil
}
if value == nil {
return nil, nil
}
rv := reflect.ValueOf(value)
switch rv.Type().Kind() {
case reflect.Int64:
return encBigInt(rv.Int()), nil
}
return nil, marshalErrorf("can not marshal %T into %s. Accepted types: Marshaler, int64, time.Duration, UnsetValue.", value, info)
}
func marshalTimestamp(info TypeInfo, value interface{}) ([]byte, error) {
switch v := value.(type) {
case Marshaler:
return v.MarshalCQL(info)
case unsetColumn:
return nil, nil
case int64:
return encBigInt(v), nil
case time.Time:
if v.IsZero() {
return []byte{}, nil
}
x := int64(v.UTC().Unix()*1e3) + int64(v.UTC().Nanosecond()/1e6)
return encBigInt(x), nil
}
if value == nil {
return nil, nil
}
rv := reflect.ValueOf(value)
switch rv.Type().Kind() {
case reflect.Int64:
return encBigInt(rv.Int()), nil
}
return nil, marshalErrorf("can not marshal %T into %s. Accepted types: Marshaler, int64, time.Time, UnsetValue.", value, info)
}
func unmarshalTime(info TypeInfo, data []byte, value interface{}) error {
switch v := value.(type) {
case Unmarshaler:
return v.UnmarshalCQL(info, data)
case *int64:
*v = decBigInt(data)
return nil
case *time.Duration:
*v = time.Duration(decBigInt(data))
return nil
}
rv := reflect.ValueOf(value)
if rv.Kind() != reflect.Ptr {
return unmarshalErrorf("can not unmarshal into non-pointer %T", value)
}
rv = rv.Elem()
switch rv.Type().Kind() {
case reflect.Int64:
rv.SetInt(decBigInt(data))
return nil
}
return unmarshalErrorf("can not unmarshal %s into %T. Accepted types: Unmarshaler, *int64, *time.Duration.", info, value)
}
func unmarshalTimestamp(info TypeInfo, data []byte, value interface{}) error {
switch v := value.(type) {
case Unmarshaler:
return v.UnmarshalCQL(info, data)
case *int64:
*v = decBigInt(data)
return nil
case *time.Time:
if len(data) == 0 {
*v = time.Time{}
return nil
}
x := decBigInt(data)
sec := x / 1000
nsec := (x - sec*1000) * 1000000
*v = time.Unix(sec, nsec).In(time.UTC)
return nil
}
rv := reflect.ValueOf(value)
if rv.Kind() != reflect.Ptr {
return unmarshalErrorf("can not unmarshal into non-pointer %T", value)
}
rv = rv.Elem()
switch rv.Type().Kind() {
case reflect.Int64:
rv.SetInt(decBigInt(data))
return nil
}
return unmarshalErrorf("can not unmarshal %s into %T. Accepted types: Unmarshaler, *int64, *time.Time.", info, value)
}
const millisecondsInADay int64 = 24 * 60 * 60 * 1000
func marshalDate(info TypeInfo, value interface{}) ([]byte, error) {
var timestamp int64
switch v := value.(type) {
case Marshaler:
return v.MarshalCQL(info)
case unsetColumn:
return nil, nil
case int64:
timestamp = v
x := timestamp/millisecondsInADay + int64(1<<31)
return encInt(int32(x)), nil
case time.Time:
if v.IsZero() {
return []byte{}, nil
}
timestamp = int64(v.UTC().Unix()*1e3) + int64(v.UTC().Nanosecond()/1e6)
x := timestamp/millisecondsInADay + int64(1<<31)
return encInt(int32(x)), nil
case *time.Time:
if v.IsZero() {
return []byte{}, nil
}
timestamp = int64(v.UTC().Unix()*1e3) + int64(v.UTC().Nanosecond()/1e6)
x := timestamp/millisecondsInADay + int64(1<<31)
return encInt(int32(x)), nil
case string:
if v == "" {
return []byte{}, nil
}
t, err := time.Parse("2006-01-02", v)
if err != nil {
return nil, marshalErrorf("can not marshal %T into %s, date layout must be '2006-01-02'", value, info)
}
timestamp = int64(t.UTC().Unix()*1e3) + int64(t.UTC().Nanosecond()/1e6)
x := timestamp/millisecondsInADay + int64(1<<31)
return encInt(int32(x)), nil
}
if value == nil {
return nil, nil
}
return nil, marshalErrorf("can not marshal %T into %s. Accepted types: Marshaler, int64, time.Time, *time.Time, string, UnsetValue.", value, info)
}
func unmarshalDate(info TypeInfo, data []byte, value interface{}) error {
switch v := value.(type) {
case Unmarshaler:
return v.UnmarshalCQL(info, data)
case *time.Time:
if len(data) == 0 {
*v = time.Time{}
return nil
}
var origin uint32 = 1 << 31
var current uint32 = binary.BigEndian.Uint32(data)
timestamp := (int64(current) - int64(origin)) * millisecondsInADay
*v = time.UnixMilli(timestamp).In(time.UTC)
return nil
case *string:
if len(data) == 0 {
*v = ""
return nil
}
var origin uint32 = 1 << 31
var current uint32 = binary.BigEndian.Uint32(data)
timestamp := (int64(current) - int64(origin)) * millisecondsInADay
*v = time.UnixMilli(timestamp).In(time.UTC).Format("2006-01-02")
return nil
}
return unmarshalErrorf("can not unmarshal %s into %T. Accepted types: Unmarshaler, *time.Time, *string.", info, value)
}
func marshalDuration(info TypeInfo, value interface{}) ([]byte, error) {
switch v := value.(type) {
case Marshaler:
return v.MarshalCQL(info)
case unsetColumn:
return nil, nil
case int64:
return encVints(0, 0, v), nil
case time.Duration:
return encVints(0, 0, v.Nanoseconds()), nil
case string:
d, err := time.ParseDuration(v)
if err != nil {
return nil, err
}
return encVints(0, 0, d.Nanoseconds()), nil
case Duration:
return encVints(v.Months, v.Days, v.Nanoseconds), nil
}
if value == nil {
return nil, nil
}
rv := reflect.ValueOf(value)
switch rv.Type().Kind() {
case reflect.Int64:
return encBigInt(rv.Int()), nil
}
return nil, marshalErrorf("can not marshal %T into %s. Accepted types: Marshaler, int64, time.Duration, string, Duration, UnsetValue.", value, info)
}
func unmarshalDuration(info TypeInfo, data []byte, value interface{}) error {
switch v := value.(type) {
case Unmarshaler:
return v.UnmarshalCQL(info, data)
case *Duration:
if len(data) == 0 {
*v = Duration{
Months: 0,
Days: 0,
Nanoseconds: 0,
}
return nil
}
months, days, nanos, err := decVints(data)
if err != nil {
return unmarshalErrorf("failed to unmarshal %s into %T: %s", info, value, err.Error())
}
*v = Duration{
Months: months,
Days: days,
Nanoseconds: nanos,
}
return nil
}
return unmarshalErrorf("can not unmarshal %s into %T. Accepted types: Unmarshaler, *Duration.", info, value)
}
func decVints(data []byte) (int32, int32, int64, error) {
month, i, err := decVint(data, 0)
if err != nil {
return 0, 0, 0, fmt.Errorf("failed to extract month: %s", err.Error())
}
days, i, err := decVint(data, i)
if err != nil {
return 0, 0, 0, fmt.Errorf("failed to extract days: %s", err.Error())
}
nanos, _, err := decVint(data, i)
if err != nil {
return 0, 0, 0, fmt.Errorf("failed to extract nanoseconds: %s", err.Error())
}
return int32(month), int32(days), nanos, err
}
func decVint(data []byte, start int) (int64, int, error) {
if len(data) <= start {
return 0, 0, errors.New("unexpected eof")
}
firstByte := data[start]
if firstByte&0x80 == 0 {
return decIntZigZag(uint64(firstByte)), start + 1, nil
}
numBytes := bits.LeadingZeros32(uint32(^firstByte)) - 24
ret := uint64(firstByte & (0xff >> uint(numBytes)))
if len(data) < start+numBytes+1 {
return 0, 0, fmt.Errorf("data expect to have %d bytes, but it has only %d", start+numBytes+1, len(data))
}
for i := start; i < start+numBytes; i++ {
ret <<= 8
ret |= uint64(data[i+1] & 0xff)
}
return decIntZigZag(ret), start + numBytes + 1, nil
}
func decIntZigZag(n uint64) int64 {
return int64((n >> 1) ^ -(n & 1))
}
func encIntZigZag(n int64) uint64 {
return uint64((n >> 63) ^ (n << 1))
}
func encVints(months int32, seconds int32, nanos int64) []byte {
buf := append(encVint(int64(months)), encVint(int64(seconds))...)
return append(buf, encVint(nanos)...)
}
func encVint(v int64) []byte {
vEnc := encIntZigZag(v)
lead0 := bits.LeadingZeros64(vEnc)
numBytes := (639 - lead0*9) >> 6
// It can be 1 or 0 is v ==0
if numBytes <= 1 {
return []byte{byte(vEnc)}
}
extraBytes := numBytes - 1
var buf = make([]byte, numBytes)
for i := extraBytes; i >= 0; i-- {
buf[i] = byte(vEnc)
vEnc >>= 8
}
buf[0] |= byte(^(0xff >> uint(extraBytes)))
return buf
}
func writeCollectionSize(info CollectionType, n int, buf *bytes.Buffer) error {
if info.proto > protoVersion2 {
if n > math.MaxInt32 {
return marshalErrorf("marshal: collection too large")
}
buf.WriteByte(byte(n >> 24))
buf.WriteByte(byte(n >> 16))
buf.WriteByte(byte(n >> 8))
buf.WriteByte(byte(n))
} else {
if n > math.MaxUint16 {
return marshalErrorf("marshal: collection too large")
}
buf.WriteByte(byte(n >> 8))
buf.WriteByte(byte(n))
}
return nil
}
func marshalList(info TypeInfo, value interface{}) ([]byte, error) {
listInfo, ok := info.(CollectionType)
if !ok {
return nil, marshalErrorf("marshal: can not marshal non collection type into list")
}
if value == nil {
return nil, nil
} else if _, ok := value.(unsetColumn); ok {
return nil, nil
}
rv := reflect.ValueOf(value)
t := rv.Type()
k := t.Kind()
if k == reflect.Slice && rv.IsNil() {
return nil, nil
}
switch k {
case reflect.Slice, reflect.Array:
buf := &bytes.Buffer{}
n := rv.Len()
if err := writeCollectionSize(listInfo, n, buf); err != nil {
return nil, err
}
for i := 0; i < n; i++ {
item, err := Marshal(listInfo.Elem, rv.Index(i).Interface())
if err != nil {
return nil, err
}
itemLen := len(item)
// Set the value to null for supported protocols
if item == nil && listInfo.proto > protoVersion2 {
itemLen = -1
}
if err := writeCollectionSize(listInfo, itemLen, buf); err != nil {
return nil, err
}
buf.Write(item)
}
return buf.Bytes(), nil
case reflect.Map:
elem := t.Elem()
if elem.Kind() == reflect.Struct && elem.NumField() == 0 {
rkeys := rv.MapKeys()
keys := make([]interface{}, len(rkeys))
for i := 0; i < len(keys); i++ {
keys[i] = rkeys[i].Interface()
}
return marshalList(listInfo, keys)
}
}
return nil, marshalErrorf("can not marshal %T into %s. Accepted types: slice, array, map[]struct.", value, info)
}
func readCollectionSize(info CollectionType, data []byte) (size, read int, err error) {
if info.proto > protoVersion2 {
if len(data) < 4 {
return 0, 0, unmarshalErrorf("unmarshal list: unexpected eof")
}
size = int(int32(data[0])<<24 | int32(data[1])<<16 | int32(data[2])<<8 | int32(data[3]))
read = 4
} else {
if len(data) < 2 {
return 0, 0, unmarshalErrorf("unmarshal list: unexpected eof")
}
size = int(data[0])<<8 | int(data[1])
read = 2
}
return
}
func unmarshalList(info TypeInfo, data []byte, value interface{}) error {
listInfo, ok := info.(CollectionType)
if !ok {
return unmarshalErrorf("unmarshal: can not unmarshal none collection type into list")
}
rv := reflect.ValueOf(value)
if rv.Kind() != reflect.Ptr {
return unmarshalErrorf("can not unmarshal into non-pointer %T", value)
}
rv = rv.Elem()
t := rv.Type()
k := t.Kind()
switch k {
case reflect.Slice, reflect.Array:
if data == nil {
if k == reflect.Array {
return unmarshalErrorf("unmarshal list: can not store nil in array value")
}
if rv.IsNil() {
return nil
}
rv.Set(reflect.Zero(t))
return nil
}
n, p, err := readCollectionSize(listInfo, data)
if err != nil {
return err
}
data = data[p:]
if k == reflect.Array {
if rv.Len() != n {
return unmarshalErrorf("unmarshal list: array with wrong size")
}
} else {
rv.Set(reflect.MakeSlice(t, n, n))
}
for i := 0; i < n; i++ {
m, p, err := readCollectionSize(listInfo, data)
if err != nil {
return err
}
data = data[p:]
// In case m < 0, the value is null, and unmarshalData should be nil.
var unmarshalData []byte
if m >= 0 {
if len(data) < m {
return unmarshalErrorf("unmarshal list: unexpected eof")
}
unmarshalData = data[:m]
data = data[m:]
}
if err := Unmarshal(listInfo.Elem, unmarshalData, rv.Index(i).Addr().Interface()); err != nil {
return err
}
}
return nil
}
return unmarshalErrorf("can not unmarshal %s into %T. Accepted types: *slice, *array.", info, value)
}
func marshalVector(info VectorType, value interface{}) ([]byte, error) {
if value == nil {
return nil, nil
} else if _, ok := value.(unsetColumn); ok {
return nil, nil
}
rv := reflect.ValueOf(value)
t := rv.Type()
k := t.Kind()
if k == reflect.Slice && rv.IsNil() {
return nil, nil
}
switch k {
case reflect.Slice, reflect.Array:
buf := &bytes.Buffer{}
n := rv.Len()
if n != info.Dimensions {
return nil, marshalErrorf("expected vector with %d dimensions, received %d", info.Dimensions, n)
}
for i := 0; i < n; i++ {
item, err := Marshal(info.SubType, rv.Index(i).Interface())
if err != nil {
return nil, err
}
if isVectorVariableLengthType(info.SubType) {
writeUnsignedVInt(buf, uint64(len(item)))
}
buf.Write(item)
}
return buf.Bytes(), nil
}
return nil, marshalErrorf("can not marshal %T into %s. Accepted types: slice, array.", value, info)
}
func unmarshalVector(info VectorType, data []byte, value interface{}) error {
rv := reflect.ValueOf(value)
if rv.Kind() != reflect.Ptr {
return unmarshalErrorf("can not unmarshal into non-pointer %T", value)
}
rv = rv.Elem()
t := rv.Type()
k := t.Kind()
switch k {
case reflect.Slice, reflect.Array:
if data == nil {
if k == reflect.Array {
return unmarshalErrorf("unmarshal vector: can not store nil in array value")
}
if rv.IsNil() {
return nil
}
rv.Set(reflect.Zero(t))
return nil
}
if k == reflect.Array {
if rv.Len() != info.Dimensions {
return unmarshalErrorf("unmarshal vector: array of size %d cannot store vector of %d dimensions", rv.Len(), info.Dimensions)
}
} else {
rv.Set(reflect.MakeSlice(t, info.Dimensions, info.Dimensions))
}
elemSize := len(data) / info.Dimensions
for i := 0; i < info.Dimensions; i++ {
offset := 0
if isVectorVariableLengthType(info.SubType) {
m, p, err := readUnsignedVInt(data)
if err != nil {
return err
}
elemSize = int(m)
offset = p
}
if offset > 0 {
data = data[offset:]
}
var unmarshalData []byte
if elemSize >= 0 {
if len(data) < elemSize {
return unmarshalErrorf("unmarshal vector: unexpected eof")
}
unmarshalData = data[:elemSize]
data = data[elemSize:]
}
err := Unmarshal(info.SubType, unmarshalData, rv.Index(i).Addr().Interface())
if err != nil {
return unmarshalErrorf("failed to unmarshal %s into %T: %s", info.SubType, unmarshalData, err.Error())
}
}
return nil
}
return unmarshalErrorf("can not unmarshal %s into %T. Accepted types: slice, array.", info, value)
}
// isVectorVariableLengthType determines if a type requires explicit length serialization within a vector.
// Variable-length types need their length encoded before the actual data to allow proper deserialization.
// Fixed-length types, on the other hand, don't require this kind of length prefix.
func isVectorVariableLengthType(elemType TypeInfo) bool {
switch elemType.Type() {
case TypeVarchar, TypeAscii, TypeBlob, TypeText,
TypeCounter,
TypeDuration, TypeDate, TypeTime,
TypeDecimal, TypeSmallInt, TypeTinyInt, TypeVarint,
TypeInet,
TypeList, TypeSet, TypeMap, TypeUDT, TypeTuple:
return true
case TypeCustom:
if vecType, ok := elemType.(VectorType); ok {
return isVectorVariableLengthType(vecType.SubType)
}
return true
}
return false
}
func writeUnsignedVInt(buf *bytes.Buffer, v uint64) {
numBytes := computeUnsignedVIntSize(v)
if numBytes <= 1 {
buf.WriteByte(byte(v))
return
}
extraBytes := numBytes - 1
var tmp = make([]byte, numBytes)
for i := extraBytes; i >= 0; i-- {
tmp[i] = byte(v)
v >>= 8
}
tmp[0] |= byte(^(0xff >> uint(extraBytes)))
buf.Write(tmp)
}
func readUnsignedVInt(data []byte) (uint64, int, error) {
if len(data) <= 0 {
return 0, 0, errors.New("unexpected eof")
}
firstByte := data[0]
if firstByte&0x80 == 0 {
return uint64(firstByte), 1, nil
}
numBytes := bits.LeadingZeros32(uint32(^firstByte)) - 24
ret := uint64(firstByte & (0xff >> uint(numBytes)))
if len(data) < numBytes+1 {
return 0, 0, fmt.Errorf("data expect to have %d bytes, but it has only %d", numBytes+1, len(data))
}
for i := 0; i < numBytes; i++ {
ret <<= 8
ret |= uint64(data[i+1] & 0xff)
}
return ret, numBytes + 1, nil
}
func computeUnsignedVIntSize(v uint64) int {
lead0 := bits.LeadingZeros64(v)
return (639 - lead0*9) >> 6
}
func marshalMap(info TypeInfo, value interface{}) ([]byte, error) {
mapInfo, ok := info.(CollectionType)
if !ok {
return nil, marshalErrorf("marshal: can not marshal none collection type into map")
}
if value == nil {
return nil, nil
} else if _, ok := value.(unsetColumn); ok {
return nil, nil
}
rv := reflect.ValueOf(value)
t := rv.Type()
if t.Kind() != reflect.Map {
return nil, marshalErrorf("can not marshal %T into %s", value, info)
}
if rv.IsNil() {
return nil, nil
}
buf := &bytes.Buffer{}
n := rv.Len()
if err := writeCollectionSize(mapInfo, n, buf); err != nil {
return nil, err
}
keys := rv.MapKeys()
for _, key := range keys {
item, err := Marshal(mapInfo.Key, key.Interface())
if err != nil {
return nil, err
}
itemLen := len(item)
// Set the key to null for supported protocols
if item == nil && mapInfo.proto > protoVersion2 {
itemLen = -1
}
if err := writeCollectionSize(mapInfo, itemLen, buf); err != nil {
return nil, err
}
buf.Write(item)
item, err = Marshal(mapInfo.Elem, rv.MapIndex(key).Interface())
if err != nil {
return nil, err
}
itemLen = len(item)
// Set the value to null for supported protocols
if item == nil && mapInfo.proto > protoVersion2 {
itemLen = -1
}
if err := writeCollectionSize(mapInfo, itemLen, buf); err != nil {
return nil, err
}
buf.Write(item)
}
return buf.Bytes(), nil
}
func unmarshalMap(info TypeInfo, data []byte, value interface{}) error {
mapInfo, ok := info.(CollectionType)
if !ok {
return unmarshalErrorf("unmarshal: can not unmarshal none collection type into map")
}
rv := reflect.ValueOf(value)
if rv.Kind() != reflect.Ptr {
return unmarshalErrorf("can not unmarshal into non-pointer %T", value)
}
rv = rv.Elem()
t := rv.Type()
if t.Kind() != reflect.Map {
return unmarshalErrorf("can not unmarshal %s into %T", info, value)
}
if data == nil {
rv.Set(reflect.Zero(t))
return nil
}
n, p, err := readCollectionSize(mapInfo, data)
if err != nil {
return err
}
if n < 0 {
return unmarshalErrorf("negative map size %d", n)
}
rv.Set(reflect.MakeMapWithSize(t, n))
data = data[p:]
for i := 0; i < n; i++ {
m, p, err := readCollectionSize(mapInfo, data)
if err != nil {
return err
}
data = data[p:]
key := reflect.New(t.Key())
// In case m < 0, the key is null, and unmarshalData should be nil.
var unmarshalData []byte
if m >= 0 {
if len(data) < m {
return unmarshalErrorf("unmarshal map: unexpected eof")
}
unmarshalData = data[:m]
data = data[m:]
}
if err := Unmarshal(mapInfo.Key, unmarshalData, key.Interface()); err != nil {
return err
}
m, p, err = readCollectionSize(mapInfo, data)
if err != nil {
return err
}
data = data[p:]
val := reflect.New(t.Elem())
// In case m < 0, the value is null, and unmarshalData should be nil.
unmarshalData = nil
if m >= 0 {
if len(data) < m {
return unmarshalErrorf("unmarshal map: unexpected eof")
}
unmarshalData = data[:m]
data = data[m:]
}
if err := Unmarshal(mapInfo.Elem, unmarshalData, val.Interface()); err != nil {
return err
}
rv.SetMapIndex(key.Elem(), val.Elem())
}
return nil
}
func marshalUUID(info TypeInfo, value interface{}) ([]byte, error) {
switch val := value.(type) {
case unsetColumn:
return nil, nil
case UUID:
return val.Bytes(), nil
case [16]byte:
return val[:], nil
case []byte:
if len(val) != 16 {
return nil, marshalErrorf("can not marshal []byte %d bytes long into %s, must be exactly 16 bytes long", len(val), info)
}
return val, nil
case string:
b, err := ParseUUID(val)
if err != nil {
return nil, err
}
return b[:], nil
}
if value == nil {
return nil, nil
}
return nil, marshalErrorf("can not marshal %T into %s. Accepted types: UUID, [16]byte, string, UnsetValue.", value, info)
}
func unmarshalUUID(info TypeInfo, data []byte, value interface{}) error {
if len(data) == 0 {
switch v := value.(type) {
case *string:
*v = ""
case *[]byte:
*v = nil
case *UUID:
*v = UUID{}
default:
return unmarshalErrorf("can not unmarshal X %s into %T. Accepted types: *UUID, *[]byte, *string.", info, value)
}
return nil
}
if len(data) != 16 {
return unmarshalErrorf("unable to parse UUID: UUIDs must be exactly 16 bytes long")
}
switch v := value.(type) {
case *[16]byte:
copy((*v)[:], data)
return nil
case *UUID:
copy((*v)[:], data)
return nil
}
u, err := UUIDFromBytes(data)
if err != nil {
return unmarshalErrorf("unable to parse UUID: %s", err)
}
switch v := value.(type) {
case *string:
*v = u.String()
return nil
case *[]byte:
*v = u[:]
return nil
}
return unmarshalErrorf("can not unmarshal X %s into %T. Accepted types: *UUID, *[]byte, *string.", info, value)
}
func unmarshalTimeUUID(info TypeInfo, data []byte, value interface{}) error {
switch v := value.(type) {
case Unmarshaler:
return v.UnmarshalCQL(info, data)
case *time.Time:
id, err := UUIDFromBytes(data)
if err != nil {
return err
} else if id.Version() != 1 {
return unmarshalErrorf("invalid timeuuid")
}
*v = id.Time()
return nil
default:
return unmarshalUUID(info, data, value)
}
}
func marshalInet(info TypeInfo, value interface{}) ([]byte, error) {
// we return either the 4 or 16 byte representation of an
// ip address here otherwise the db value will be prefixed
// with the remaining byte values e.g. ::ffff:127.0.0.1 and not 127.0.0.1
switch val := value.(type) {
case unsetColumn:
return nil, nil
case net.IP:
t := val.To4()
if t == nil {
return val.To16(), nil
}
return t, nil
case string:
b := net.ParseIP(val)
if b != nil {
t := b.To4()
if t == nil {
return b.To16(), nil
}
return t, nil
}
return nil, marshalErrorf("cannot marshal. invalid ip string %s", val)
}
if value == nil {
return nil, nil
}
return nil, marshalErrorf("cannot marshal %T into %s. Accepted types: net.IP, string.", value, info)
}
func unmarshalInet(info TypeInfo, data []byte, value interface{}) error {
switch v := value.(type) {
case Unmarshaler:
return v.UnmarshalCQL(info, data)
case *net.IP:
if x := len(data); !(x == 4 || x == 16) {
return unmarshalErrorf("cannot unmarshal %s into %T: invalid sized IP: got %d bytes not 4 or 16", info, value, x)
}
buf := copyBytes(data)
ip := net.IP(buf)
if v4 := ip.To4(); v4 != nil {
*v = v4
return nil
}
*v = ip
return nil
case *string:
if len(data) == 0 {
*v = ""
return nil
}
ip := net.IP(data)
if v4 := ip.To4(); v4 != nil {
*v = v4.String()
return nil
}
*v = ip.String()
return nil
}
return unmarshalErrorf("cannot unmarshal %s into %T. Accepted types: Unmarshaler, *net.IP, *string.", info, value)
}
func marshalTuple(info TypeInfo, value interface{}) ([]byte, error) {
tuple := info.(TupleTypeInfo)
switch v := value.(type) {
case unsetColumn:
return nil, unmarshalErrorf("Invalid request: UnsetValue is unsupported for tuples")
case []interface{}:
if len(v) != len(tuple.Elems) {
return nil, unmarshalErrorf("cannont marshal tuple: wrong number of elements")
}
var buf []byte
for i, elem := range v {
if elem == nil {
buf = appendInt(buf, int32(-1))
continue
}
data, err := Marshal(tuple.Elems[i], elem)
if err != nil {
return nil, err
}
n := len(data)
buf = appendInt(buf, int32(n))
buf = append(buf, data...)
}
return buf, nil
}
rv := reflect.ValueOf(value)
t := rv.Type()
k := t.Kind()
switch k {
case reflect.Struct:
if v := t.NumField(); v != len(tuple.Elems) {
return nil, marshalErrorf("can not marshal tuple into struct %v, not enough fields have %d need %d", t, v, len(tuple.Elems))
}
var buf []byte
for i, elem := range tuple.Elems {
field := rv.Field(i)
if field.Kind() == reflect.Ptr && field.IsNil() {
buf = appendInt(buf, int32(-1))
continue
}
data, err := Marshal(elem, field.Interface())
if err != nil {
return nil, err
}
n := len(data)
buf = appendInt(buf, int32(n))
buf = append(buf, data...)
}
return buf, nil
case reflect.Slice, reflect.Array:
size := rv.Len()
if size != len(tuple.Elems) {
return nil, marshalErrorf("can not marshal tuple into %v of length %d need %d elements", k, size, len(tuple.Elems))
}
var buf []byte
for i, elem := range tuple.Elems {
item := rv.Index(i)
if item.Kind() == reflect.Ptr && item.IsNil() {
buf = appendInt(buf, int32(-1))
continue
}
data, err := Marshal(elem, item.Interface())
if err != nil {
return nil, err
}
n := len(data)
buf = appendInt(buf, int32(n))
buf = append(buf, data...)
}
return buf, nil
}
return nil, marshalErrorf("cannot marshal %T into %s. Accepted types: struct, []interface{}, array, slice, UnsetValue.", value, tuple)
}
func readBytes(p []byte) ([]byte, []byte) {
// TODO: really should use a framer
size := readInt(p)
p = p[4:]
if size < 0 {
return nil, p
}
return p[:size], p[size:]
}
// currently only support unmarshal into a list of values, this makes it possible
// to support tuples without changing the query API. In the future this can be extend
// to allow unmarshalling into custom tuple types.
func unmarshalTuple(info TypeInfo, data []byte, value interface{}) error {
if v, ok := value.(Unmarshaler); ok {
return v.UnmarshalCQL(info, data)
}
tuple := info.(TupleTypeInfo)
switch v := value.(type) {
case []interface{}:
for i, elem := range tuple.Elems {
// each element inside data is a [bytes]
var p []byte
if len(data) >= 4 {
p, data = readBytes(data)
}
err := Unmarshal(elem, p, v[i])
if err != nil {
return err
}
}
return nil
}
rv := reflect.ValueOf(value)
if rv.Kind() != reflect.Ptr {
return unmarshalErrorf("can not unmarshal into non-pointer %T", value)
}
rv = rv.Elem()
t := rv.Type()
k := t.Kind()
switch k {
case reflect.Struct:
if v := t.NumField(); v != len(tuple.Elems) {
return unmarshalErrorf("can not unmarshal tuple into struct %v, not enough fields have %d need %d", t, v, len(tuple.Elems))
}
for i, elem := range tuple.Elems {
var p []byte
if len(data) >= 4 {
p, data = readBytes(data)
}
v, err := elem.NewWithError()
if err != nil {
return err
}
if err := Unmarshal(elem, p, v); err != nil {
return err
}
switch rv.Field(i).Kind() {
case reflect.Ptr:
if p != nil {
rv.Field(i).Set(reflect.ValueOf(v))
} else {
rv.Field(i).Set(reflect.Zero(reflect.TypeOf(v)))
}
default:
rv.Field(i).Set(reflect.ValueOf(v).Elem())
}
}
return nil
case reflect.Slice, reflect.Array:
if k == reflect.Array {
size := rv.Len()
if size != len(tuple.Elems) {
return unmarshalErrorf("can not unmarshal tuple into array of length %d need %d elements", size, len(tuple.Elems))
}
} else {
rv.Set(reflect.MakeSlice(t, len(tuple.Elems), len(tuple.Elems)))
}
for i, elem := range tuple.Elems {
var p []byte
if len(data) >= 4 {
p, data = readBytes(data)
}
v, err := elem.NewWithError()
if err != nil {
return err
}
if err := Unmarshal(elem, p, v); err != nil {
return err
}
switch rv.Index(i).Kind() {
case reflect.Ptr:
if p != nil {
rv.Index(i).Set(reflect.ValueOf(v))
} else {
rv.Index(i).Set(reflect.Zero(reflect.TypeOf(v)))
}
default:
rv.Index(i).Set(reflect.ValueOf(v).Elem())
}
}
return nil
}
return unmarshalErrorf("cannot unmarshal %s into %T. Accepted types: *struct, []interface{}, *array, *slice, Unmarshaler.", info, value)
}
// UDTMarshaler is an interface which should be implemented by users wishing to
// handle encoding UDT types to sent to Cassandra. Note: due to current implentations
// methods defined for this interface must be value receivers not pointer receivers.
type UDTMarshaler interface {
// MarshalUDT will be called for each field in the the UDT returned by Cassandra,
// the implementor should marshal the type to return by for example calling
// Marshal.
MarshalUDT(name string, info TypeInfo) ([]byte, error)
}
// UDTUnmarshaler should be implemented by users wanting to implement custom
// UDT unmarshaling.
type UDTUnmarshaler interface {
// UnmarshalUDT will be called for each field in the UDT return by Cassandra,
// the implementor should unmarshal the data into the value of their chosing,
// for example by calling Unmarshal.
UnmarshalUDT(name string, info TypeInfo, data []byte) error
}
func marshalUDT(info TypeInfo, value interface{}) ([]byte, error) {
udt := info.(UDTTypeInfo)
switch v := value.(type) {
case Marshaler:
return v.MarshalCQL(info)
case unsetColumn:
return nil, unmarshalErrorf("invalid request: UnsetValue is unsupported for user defined types")
case UDTMarshaler:
var buf []byte
for _, e := range udt.Elements {
data, err := v.MarshalUDT(e.Name, e.Type)
if err != nil {
return nil, err
}
buf = appendBytes(buf, data)
}
return buf, nil
case map[string]interface{}:
var buf []byte
for _, e := range udt.Elements {
val, ok := v[e.Name]
var data []byte
if ok {
var err error
data, err = Marshal(e.Type, val)
if err != nil {
return nil, err
}
}
buf = appendBytes(buf, data)
}
return buf, nil
}
k := reflect.ValueOf(value)
if k.Kind() == reflect.Ptr {
if k.IsNil() {
return nil, marshalErrorf("cannot marshal %T into %s", value, info)
}
k = k.Elem()
}
if k.Kind() != reflect.Struct || !k.IsValid() {
return nil, marshalErrorf("cannot marshal %T into %s. Accepted types: Marshaler, UDTMarshaler, map[string]interface{}, struct, UnsetValue.", value, info)
}
fields := make(map[string]reflect.Value)
t := reflect.TypeOf(value)
for i := 0; i < t.NumField(); i++ {
sf := t.Field(i)
if tag := sf.Tag.Get("cql"); tag != "" {
fields[tag] = k.Field(i)
}
}
var buf []byte
for _, e := range udt.Elements {
f, ok := fields[e.Name]
if !ok {
f = k.FieldByName(e.Name)
}
var data []byte
if f.IsValid() && f.CanInterface() {
var err error
data, err = Marshal(e.Type, f.Interface())
if err != nil {
return nil, err
}
}
buf = appendBytes(buf, data)
}
return buf, nil
}
func unmarshalUDT(info TypeInfo, data []byte, value interface{}) error {
switch v := value.(type) {
case Unmarshaler:
return v.UnmarshalCQL(info, data)
case UDTUnmarshaler:
udt := info.(UDTTypeInfo)
for id, e := range udt.Elements {
if len(data) == 0 {
return nil
}
if len(data) < 4 {
return unmarshalErrorf("can not unmarshal %s: field [%d]%s: unexpected eof", info, id, e.Name)
}
var p []byte
p, data = readBytes(data)
if err := v.UnmarshalUDT(e.Name, e.Type, p); err != nil {
return err
}
}
return nil
case *map[string]interface{}:
udt := info.(UDTTypeInfo)
rv := reflect.ValueOf(value)
if rv.Kind() != reflect.Ptr {
return unmarshalErrorf("can not unmarshal into non-pointer %T", value)
}
rv = rv.Elem()
t := rv.Type()
if t.Kind() != reflect.Map {
return unmarshalErrorf("can not unmarshal %s into %T. Accepted types: Unmarshaler, UDTUnmarshaler, *map[string]interface{}, struct.", info, value)
} else if data == nil {
rv.Set(reflect.Zero(t))
return nil
}
rv.Set(reflect.MakeMap(t))
m := *v
for id, e := range udt.Elements {
if len(data) == 0 {
return nil
}
if len(data) < 4 {
return unmarshalErrorf("can not unmarshal %s: field [%d]%s: unexpected eof", info, id, e.Name)
}
valType, err := goType(e.Type)
if err != nil {
return unmarshalErrorf("can not unmarshal %s: %v", info, err)
}
val := reflect.New(valType)
var p []byte
p, data = readBytes(data)
if err := Unmarshal(e.Type, p, val.Interface()); err != nil {
return err
}
m[e.Name] = val.Elem().Interface()
}
return nil
}
rv := reflect.ValueOf(value)
if rv.Kind() != reflect.Ptr {
return unmarshalErrorf("can not unmarshal into non-pointer %T", value)
}
k := rv.Elem()
if k.Kind() != reflect.Struct || !k.IsValid() {
return unmarshalErrorf("cannot unmarshal %s into %T. Accepted types: Unmarshaler, UDTUnmarshaler, *map[string]interface{}, *struct.", info, value)
}
if len(data) == 0 {
if k.CanSet() {
k.Set(reflect.Zero(k.Type()))
}
return nil
}
t := k.Type()
fields := make(map[string]reflect.Value, t.NumField())
for i := 0; i < t.NumField(); i++ {
sf := t.Field(i)
if tag := sf.Tag.Get("cql"); tag != "" {
fields[tag] = k.Field(i)
}
}
udt := info.(UDTTypeInfo)
for id, e := range udt.Elements {
if len(data) == 0 {
return nil
}
if len(data) < 4 {
// UDT def does not match the column value
return unmarshalErrorf("can not unmarshal %s: field [%d]%s: unexpected eof", info, id, e.Name)
}
var p []byte
p, data = readBytes(data)
f, ok := fields[e.Name]
if !ok {
f = k.FieldByName(e.Name)
if f == emptyValue {
// skip fields which exist in the UDT but not in
// the struct passed in
continue
}
}
if !f.IsValid() || !f.CanAddr() {
return unmarshalErrorf("cannot unmarshal %s into %T: field %v is not valid", info, value, e.Name)
}
fk := f.Addr().Interface()
if err := Unmarshal(e.Type, p, fk); err != nil {
return err
}
}
return nil
}
// TypeInfo describes a Cassandra specific data type.
type TypeInfo interface {
Type() Type
Version() byte
Custom() string
// NewWithError creates a pointer to an empty version of whatever type
// is referenced by the TypeInfo receiver.
//
// If there is no corresponding Go type for the CQL type, NewWithError returns an error.
NewWithError() (interface{}, error)
}
type NativeType struct {
proto byte
typ Type
custom string // only used for TypeCustom
}
func NewNativeType(proto byte, typ Type) NativeType {
return NativeType{proto, typ, ""}
}
func NewCustomType(proto byte, typ Type, custom string) NativeType {
return NativeType{proto, typ, custom}
}
func (t NativeType) NewWithError() (interface{}, error) {
typ, err := goType(t)
if err != nil {
return nil, err
}
return reflect.New(typ).Interface(), nil
}
func (s NativeType) Type() Type {
return s.typ
}
func (s NativeType) Version() byte {
return s.proto
}
func (s NativeType) Custom() string {
return s.custom
}
func (s NativeType) String() string {
switch s.typ {
case TypeCustom:
return fmt.Sprintf("%s(%s)", s.typ, s.custom)
default:
return s.typ.String()
}
}
type CollectionType struct {
NativeType
Key TypeInfo // only used for TypeMap
Elem TypeInfo // only used for TypeMap, TypeList and TypeSet
}
type VectorType struct {
NativeType
SubType TypeInfo
Dimensions int
}
func (t CollectionType) NewWithError() (interface{}, error) {
typ, err := goType(t)
if err != nil {
return nil, err
}
return reflect.New(typ).Interface(), nil
}
func (c CollectionType) String() string {
switch c.typ {
case TypeMap:
return fmt.Sprintf("%s(%s, %s)", c.typ, c.Key, c.Elem)
case TypeList, TypeSet:
return fmt.Sprintf("%s(%s)", c.typ, c.Elem)
case TypeCustom:
return fmt.Sprintf("%s(%s)", c.typ, c.custom)
default:
return c.typ.String()
}
}
type TupleTypeInfo struct {
NativeType
Elems []TypeInfo
}
func (t TupleTypeInfo) String() string {
var buf bytes.Buffer
buf.WriteString(fmt.Sprintf("%s(", t.typ))
for _, elem := range t.Elems {
buf.WriteString(fmt.Sprintf("%s, ", elem))
}
buf.Truncate(buf.Len() - 2)
buf.WriteByte(')')
return buf.String()
}
func (t TupleTypeInfo) NewWithError() (interface{}, error) {
typ, err := goType(t)
if err != nil {
return nil, err
}
return reflect.New(typ).Interface(), nil
}
type UDTField struct {
Name string
Type TypeInfo
}
type UDTTypeInfo struct {
NativeType
KeySpace string
Name string
Elements []UDTField
}
func (u UDTTypeInfo) NewWithError() (interface{}, error) {
typ, err := goType(u)
if err != nil {
return nil, err
}
return reflect.New(typ).Interface(), nil
}
func (u UDTTypeInfo) String() string {
buf := &bytes.Buffer{}
fmt.Fprintf(buf, "%s.%s{", u.KeySpace, u.Name)
first := true
for _, e := range u.Elements {
if !first {
fmt.Fprint(buf, ",")
} else {
first = false
}
fmt.Fprintf(buf, "%s=%v", e.Name, e.Type)
}
fmt.Fprint(buf, "}")
return buf.String()
}
// String returns a human readable name for the Cassandra datatype
// described by t.
// Type is the identifier of a Cassandra internal datatype.
type Type int
const (
TypeCustom Type = 0x0000
TypeAscii Type = 0x0001
TypeBigInt Type = 0x0002
TypeBlob Type = 0x0003
TypeBoolean Type = 0x0004
TypeCounter Type = 0x0005
TypeDecimal Type = 0x0006
TypeDouble Type = 0x0007
TypeFloat Type = 0x0008
TypeInt Type = 0x0009
TypeText Type = 0x000A
TypeTimestamp Type = 0x000B
TypeUUID Type = 0x000C
TypeVarchar Type = 0x000D
TypeVarint Type = 0x000E
TypeTimeUUID Type = 0x000F
TypeInet Type = 0x0010
TypeDate Type = 0x0011
TypeTime Type = 0x0012
TypeSmallInt Type = 0x0013
TypeTinyInt Type = 0x0014
TypeDuration Type = 0x0015
TypeList Type = 0x0020
TypeMap Type = 0x0021
TypeSet Type = 0x0022
TypeUDT Type = 0x0030
TypeTuple Type = 0x0031
)
// String returns the name of the identifier.
func (t Type) String() string {
switch t {
case TypeCustom:
return "custom"
case TypeAscii:
return "ascii"
case TypeBigInt:
return "bigint"
case TypeBlob:
return "blob"
case TypeBoolean:
return "boolean"
case TypeCounter:
return "counter"
case TypeDecimal:
return "decimal"
case TypeDouble:
return "double"
case TypeFloat:
return "float"
case TypeInt:
return "int"
case TypeText:
return "text"
case TypeTimestamp:
return "timestamp"
case TypeUUID:
return "uuid"
case TypeVarchar:
return "varchar"
case TypeTimeUUID:
return "timeuuid"
case TypeInet:
return "inet"
case TypeDate:
return "date"
case TypeDuration:
return "duration"
case TypeTime:
return "time"
case TypeSmallInt:
return "smallint"
case TypeTinyInt:
return "tinyint"
case TypeList:
return "list"
case TypeMap:
return "map"
case TypeSet:
return "set"
case TypeVarint:
return "varint"
case TypeTuple:
return "tuple"
default:
return fmt.Sprintf("unknown_type_%d", t)
}
}
type MarshalError string
func (m MarshalError) Error() string {
return string(m)
}
func marshalErrorf(format string, args ...interface{}) MarshalError {
return MarshalError(fmt.Sprintf(format, args...))
}
type UnmarshalError string
func (m UnmarshalError) Error() string {
return string(m)
}
func unmarshalErrorf(format string, args ...interface{}) UnmarshalError {
return UnmarshalError(fmt.Sprintf(format, args...))
}