1 /*
2   Copyright (c) DataStax, Inc.
3 
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7 
8   http://www.apache.org/licenses/LICENSE-2.0
9 
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15 */
16 
17 #include "collection.hpp"
18 
19 #include "constants.hpp"
20 #include "external.hpp"
21 #include "macros.hpp"
22 #include "tuple.hpp"
23 #include "user_type_value.hpp"
24 
25 #include <string.h>
26 
27 using namespace datastax;
28 using namespace datastax::internal::core;
29 
30 extern "C" {
31 
cass_collection_new(CassCollectionType type,size_t item_count)32 CassCollection* cass_collection_new(CassCollectionType type, size_t item_count) {
33   Collection* collection = new Collection(type, item_count);
34   collection->inc_ref();
35   return CassCollection::to(collection);
36 }
37 
cass_collection_new_from_data_type(const CassDataType * data_type,size_t item_count)38 CassCollection* cass_collection_new_from_data_type(const CassDataType* data_type,
39                                                    size_t item_count) {
40   if (!data_type->is_collection()) {
41     return NULL;
42   }
43   Collection* collection = new Collection(DataType::ConstPtr(data_type), item_count);
44   collection->inc_ref();
45   return CassCollection::to(collection);
46 }
47 
cass_collection_free(CassCollection * collection)48 void cass_collection_free(CassCollection* collection) { collection->dec_ref(); }
49 
cass_collection_data_type(const CassCollection * collection)50 const CassDataType* cass_collection_data_type(const CassCollection* collection) {
51   return CassDataType::to(collection->data_type().get());
52 }
53 
54 #define CASS_COLLECTION_APPEND(Name, Params, Value)                            \
55   CassError cass_collection_append_##Name(CassCollection* collection Params) { \
56     return collection->append(Value);                                          \
57   }
58 
CASS_COLLECTION_APPEND(null,ZERO_PARAMS_ (),CassNull ())59 CASS_COLLECTION_APPEND(null, ZERO_PARAMS_(), CassNull())
60 CASS_COLLECTION_APPEND(int8, ONE_PARAM_(cass_int8_t value), value)
61 CASS_COLLECTION_APPEND(int16, ONE_PARAM_(cass_int16_t value), value)
62 CASS_COLLECTION_APPEND(int32, ONE_PARAM_(cass_int32_t value), value)
63 CASS_COLLECTION_APPEND(uint32, ONE_PARAM_(cass_uint32_t value), value)
64 CASS_COLLECTION_APPEND(int64, ONE_PARAM_(cass_int64_t value), value)
65 CASS_COLLECTION_APPEND(float, ONE_PARAM_(cass_float_t value), value)
66 CASS_COLLECTION_APPEND(double, ONE_PARAM_(cass_double_t value), value)
67 CASS_COLLECTION_APPEND(bool, ONE_PARAM_(cass_bool_t value), value)
68 CASS_COLLECTION_APPEND(uuid, ONE_PARAM_(CassUuid value), value)
69 CASS_COLLECTION_APPEND(inet, ONE_PARAM_(CassInet value), value)
70 CASS_COLLECTION_APPEND(collection, ONE_PARAM_(const CassCollection* value), value)
71 CASS_COLLECTION_APPEND(tuple, ONE_PARAM_(const CassTuple* value), value)
72 CASS_COLLECTION_APPEND(user_type, ONE_PARAM_(const CassUserType* value), value)
73 CASS_COLLECTION_APPEND(bytes, TWO_PARAMS_(const cass_byte_t* value, size_t value_size),
74                        CassBytes(value, value_size))
75 CASS_COLLECTION_APPEND(decimal,
76                        THREE_PARAMS_(const cass_byte_t* varint, size_t varint_size, int scale),
77                        CassDecimal(varint, varint_size, scale))
78 CASS_COLLECTION_APPEND(duration,
79                        THREE_PARAMS_(cass_int32_t months, cass_int32_t days, cass_int64_t nanos),
80                        CassDuration(months, days, nanos))
81 
82 #undef CASS_COLLECTION_APPEND
83 
84 CassError cass_collection_append_string(CassCollection* collection, const char* value) {
85   return collection->append(CassString(value, SAFE_STRLEN(value)));
86 }
87 
cass_collection_append_string_n(CassCollection * collection,const char * value,size_t value_length)88 CassError cass_collection_append_string_n(CassCollection* collection, const char* value,
89                                           size_t value_length) {
90   return collection->append(CassString(value, value_length));
91 }
92 
cass_collection_append_custom(CassCollection * collection,const char * class_name,const cass_byte_t * value,size_t value_size)93 CassError cass_collection_append_custom(CassCollection* collection, const char* class_name,
94                                         const cass_byte_t* value, size_t value_size) {
95   return collection->append(CassCustom(StringRef(class_name), value, value_size));
96 }
97 
cass_collection_append_custom_n(CassCollection * collection,const char * class_name,size_t class_name_length,const cass_byte_t * value,size_t value_size)98 CassError cass_collection_append_custom_n(CassCollection* collection, const char* class_name,
99                                           size_t class_name_length, const cass_byte_t* value,
100                                           size_t value_size) {
101   return collection->append(
102       CassCustom(StringRef(class_name, class_name_length), value, value_size));
103 }
104 
105 } // extern "C"
106 
append(CassNull value)107 CassError Collection::append(CassNull value) {
108   CASS_COLLECTION_CHECK_TYPE(value);
109   items_.push_back(Buffer());
110   return CASS_OK;
111 }
112 
append(const Collection * value)113 CassError Collection::append(const Collection* value) {
114   CASS_COLLECTION_CHECK_TYPE(value);
115   items_.push_back(value->encode());
116   return CASS_OK;
117 }
118 
append(const Tuple * value)119 CassError Collection::append(const Tuple* value) {
120   CASS_COLLECTION_CHECK_TYPE(value);
121   items_.push_back(value->encode());
122   return CASS_OK;
123 }
124 
append(const UserTypeValue * value)125 CassError Collection::append(const UserTypeValue* value) {
126   CASS_COLLECTION_CHECK_TYPE(value);
127   items_.push_back(value->encode());
128   return CASS_OK;
129 }
130 
get_items_size() const131 size_t Collection::get_items_size() const {
132   size_t size = 0;
133   for (BufferVec::const_iterator i = items_.begin(), end = items_.end(); i != end; ++i) {
134     size += sizeof(int32_t);
135     size += i->size();
136   }
137   return size;
138 }
139 
encode_items(char * buf) const140 void Collection::encode_items(char* buf) const {
141   for (BufferVec::const_iterator i = items_.begin(), end = items_.end(); i != end; ++i) {
142     encode_int32(buf, i->size());
143     buf += sizeof(int32_t);
144     memcpy(buf, i->data(), i->size());
145     buf += i->size();
146   }
147 }
148 
get_size() const149 size_t Collection::get_size() const { return sizeof(int32_t) + get_items_size(); }
150 
get_size_with_length() const151 size_t Collection::get_size_with_length() const { return sizeof(int32_t) + get_size(); }
152 
encode() const153 Buffer Collection::encode() const {
154   Buffer buf(get_size());
155   size_t pos = buf.encode_int32(0, get_count());
156   encode_items(buf.data() + pos);
157   return buf;
158 }
159 
encode_with_length() const160 Buffer Collection::encode_with_length() const {
161   size_t internal_size = get_size();
162   Buffer buf(sizeof(int32_t) + internal_size);
163   size_t pos = buf.encode_int32(0, internal_size);
164   pos = buf.encode_int32(pos, get_count());
165   encode_items(buf.data() + pos);
166   return buf;
167 }
168