cassandra_proto/
macros.rs

1#[macro_export]
2macro_rules! query_values {
3    ($($value:expr),*) => {
4        {
5            use cdrs::types::value::Value;
6            use cdrs::query::QueryValues;
7            let mut values: Vec<Value> = Vec::new();
8            $(
9                values.push($value.into());
10            )*
11            QueryValues::SimpleValues(values)
12        }
13    };
14    ($($name:expr => $value:expr),*) => {
15        {
16            use cdrs::types::value::Value;
17            use cdrs::query::QueryValues;
18            use std::collections::HashMap;
19            let mut values: HashMap<String, Value> = HashMap::new();
20            $(
21                values.insert($name.to_string(), $value.into());
22            )*
23            QueryValues::NamedValues(values)
24        }
25    };
26}
27
28#[macro_export]
29macro_rules! builder_opt_field {
30    ($field:ident, $field_type:ty) => {
31        pub fn $field(mut self,
32                          $field: $field_type) -> Self {
33            self.$field = Some($field);
34            self
35        }
36    };
37}
38
39#[macro_export]
40macro_rules! list_as_rust {
41    ($($into_type:tt)+) => (
42        impl AsRustType<Vec<$($into_type)+>> for List {
43            fn as_rust_type(&self) -> Result<Option<Vec<$($into_type)+>>> {
44                match self.metadata.value {
45                    Some(ColTypeOptionValue::CList(ref type_option)) |
46                    Some(ColTypeOptionValue::CSet(ref type_option)) => {
47                        let type_option_ref = type_option.as_ref();
48                        let convert = self
49                            .map(|bytes| {
50                                as_rust_type!(type_option_ref, bytes, $($into_type)+)
51                                    .unwrap()
52                                    // item in a list supposed to be a non-null value.
53                                    // TODO: check if it's true
54                                    .unwrap()
55                            });
56
57                        Ok(Some(convert))
58                    },
59                    _ => Err(Error::General(format!("Invalid conversion. \
60                            Cannot convert {:?} into List (valid types: List, Set).",
61                            self.metadata.value)))
62                }
63            }
64        }
65    );
66}
67
68#[macro_export]
69macro_rules! map_as_rust {
70    ({ $($key_type:tt)+ }, { $($val_type:tt)+ }) => (
71        impl AsRustType<HashMap<$($key_type)+, $($val_type)+>> for Map {
72            /// Converts `Map` into `HashMap` for blob values.
73            fn as_rust_type(&self) -> Result<Option<HashMap<$($key_type)+, $($val_type)+>>> {
74                match self.metadata.value {
75                    Some(ColTypeOptionValue::CMap((ref key_type_option, ref val_type_option))) => {
76                        let mut map = HashMap::with_capacity(self.data.len());
77
78                        for &(ref key, ref val) in self.data.iter() {
79                            let key_type_option = key_type_option.as_ref();
80                            let val_type_option = val_type_option.as_ref();
81                            let key = as_rust_type!(key_type_option, key, $($key_type)+)?;
82                            let val = as_rust_type!(val_type_option, val, $($val_type)+)?;
83                            if val.is_some() && key.is_some() {
84                                map.insert(key.unwrap(), val.unwrap());
85                            }
86                        }
87
88                        Ok(Some(map))
89                    }
90                    _ => unreachable!()
91                }
92            }
93        }
94    );
95}
96
97#[macro_export]
98macro_rules! into_rust_by_name {
99    (Row, $($into_type:tt)+) => (
100        impl IntoRustByName<$($into_type)+> for Row {
101            fn get_by_name(&self, name: &str) -> Result<Option<$($into_type)+>> {
102                self.get_col_spec_by_name(name)
103                    .ok_or(column_is_empty_err(name))
104                    .and_then(|(col_spec, cbytes)| {
105                        let ref col_type = col_spec.col_type;
106                        as_rust_type!(col_type, cbytes, $($into_type)+)
107                    })
108            }
109        }
110    );
111    (UDT, $($into_type:tt)+) => (
112        impl IntoRustByName<$($into_type)+> for UDT {
113            fn get_by_name(&self, name: &str) -> Result<Option<$($into_type)+>> {
114                self.data.get(name)
115                .ok_or(column_is_empty_err(name))
116                .and_then(|v| {
117                    let &(ref col_type, ref bytes) = v;
118                    let converted = as_rust_type!(col_type, bytes, $($into_type)+);
119                    converted.map_err(|err| err.into())
120                })
121            }
122        }
123    );
124}
125
126#[macro_export]
127macro_rules! into_rust_by_index {
128    (Tuple, $($into_type:tt)+) => (
129        impl IntoRustByIndex<$($into_type)+> for Tuple {
130            fn get_by_index(&self, index: usize) -> Result<Option<$($into_type)+>> {
131                self.data
132                    .get(index)
133                    .ok_or(column_is_empty_err(index))
134                    .and_then(|v| {
135                        let &(ref col_type, ref bytes) = v;
136                        let converted = as_rust_type!(col_type, bytes, $($into_type)+);
137                        converted.map_err(|err| err.into())
138                    })
139            }
140        }
141    );
142    (Row, $($into_type:tt)+) => (
143        impl IntoRustByIndex<$($into_type)+> for Row {
144            fn get_by_index(&self, index: usize) -> Result<Option<$($into_type)+>> {
145                self.get_col_spec_by_index(index)
146                    .ok_or(column_is_empty_err(index))
147                    .and_then(|(col_spec, cbytes)| {
148                        let ref col_type = col_spec.col_type;
149                        as_rust_type!(col_type, cbytes, $($into_type)+)
150                    })
151            }
152        }
153    );
154}
155
156#[macro_export]
157macro_rules! as_res_opt {
158    ($data_value:ident, $deserialize:expr) => {
159        match $data_value.as_plain() {
160            Some(ref bytes) => ($deserialize)(bytes).map(|v| Some(v)).map_err(Into::into),
161            None => Ok(None),
162        }
163    };
164}
165
166/// Decodes any Cassandra data type into the corresponding Rust type,
167/// given the column type as `ColTypeOption` and the value as `CBytes`
168/// plus the matching Rust type.
169#[macro_export]
170macro_rules! as_rust_type {
171    ($data_type_option:ident, $data_value:ident, Blob) => {
172        match $data_type_option.id {
173            ColType::Blob => as_res_opt!($data_value, decode_blob),
174            _ => Err(Error::General(format!(
175                "Invalid conversion. \
176                 Cannot convert {:?} into Vec<u8> (valid types: Blob).",
177                $data_type_option.id
178            ))),
179        }
180    };
181    ($data_type_option:ident, $data_value:ident, String) => {
182        match $data_type_option.id {
183            ColType::Custom => as_res_opt!($data_value, decode_custom),
184            ColType::Ascii => as_res_opt!($data_value, decode_ascii),
185            ColType::Varchar => as_res_opt!($data_value, decode_varchar),
186            // TODO: clarify when to use decode_text.
187            // it's not mentioned in
188            // https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L582
189            // ColType::XXX => decode_text($data_value)?
190            _ => Err(Error::General(format!(
191                "Invalid conversion. \
192                 Cannot convert {:?} into String (valid types: Custom, Ascii, Varchar).",
193                $data_type_option.id
194            ))),
195        }
196    };
197    ($data_type_option:ident, $data_value:ident, bool) => {
198        match $data_type_option.id {
199            ColType::Boolean => as_res_opt!($data_value, decode_boolean),
200            _ => Err(Error::General(format!(
201                "Invalid conversion. \
202                 Cannot convert {:?} into bool (valid types: Boolean).",
203                $data_type_option.id
204            ))),
205        }
206    };
207    ($data_type_option:ident, $data_value:ident, i64) => {
208        match $data_type_option.id {
209            ColType::Bigint => as_res_opt!($data_value, decode_bigint),
210            ColType::Timestamp => as_res_opt!($data_value, decode_timestamp),
211            ColType::Time => as_res_opt!($data_value, decode_time),
212            ColType::Varint => as_res_opt!($data_value, decode_varint),
213            ColType::Counter => as_res_opt!($data_value, decode_bigint),
214            _ => Err(Error::General(format!(
215                "Invalid conversion. \
216                 Cannot convert {:?} into i64 (valid types: Bigint, Timestamp, Time, Variant,\
217                 Counter).",
218                $data_type_option.id
219            ))),
220        }
221    };
222    ($data_type_option:ident, $data_value:ident, i32) => {
223        match $data_type_option.id {
224            ColType::Int => as_res_opt!($data_value, decode_int),
225            ColType::Date => as_res_opt!($data_value, decode_date),
226            _ => Err(Error::General(format!(
227                "Invalid conversion. \
228                 Cannot convert {:?} into i32 (valid types: Int, Date).",
229                $data_type_option.id
230            ))),
231        }
232    };
233    ($data_type_option:ident, $data_value:ident, i16) => {
234        match $data_type_option.id {
235            ColType::Smallint => as_res_opt!($data_value, decode_smallint),
236            _ => Err(Error::General(format!(
237                "Invalid conversion. \
238                 Cannot convert {:?} into i16 (valid types: Smallint).",
239                $data_type_option.id
240            ))),
241        }
242    };
243    ($data_type_option:ident, $data_value:ident, i8) => {
244        match $data_type_option.id {
245            ColType::Tinyint => as_res_opt!($data_value, decode_tinyint),
246            _ => Err(Error::General(format!(
247                "Invalid conversion. \
248                 Cannot convert {:?} into i8 (valid types: Tinyint).",
249                $data_type_option.id
250            ))),
251        }
252    };
253    ($data_type_option:ident, $data_value:ident, f64) => {
254        match $data_type_option.id {
255            ColType::Double => as_res_opt!($data_value, decode_double),
256            _ => Err(Error::General(format!(
257                "Invalid conversion. \
258                 Cannot convert {:?} into f64 (valid types: Double).",
259                $data_type_option.id
260            ))),
261        }
262    };
263    ($data_type_option:ident, $data_value:ident, f32) => {
264        match $data_type_option.id {
265            ColType::Float => as_res_opt!($data_value, decode_float),
266            _ => Err(Error::General(format!(
267                "Invalid conversion. \
268                 Cannot convert {:?} into f32 (valid types: Float).",
269                $data_type_option.id
270            ))),
271        }
272    };
273    ($data_type_option:ident, $data_value:ident, IpAddr) => {
274        match $data_type_option.id {
275            ColType::Inet => as_res_opt!($data_value, decode_inet),
276            _ => Err(Error::General(format!(
277                "Invalid conversion. \
278                 Cannot convert {:?} into IpAddr (valid types: Inet).",
279                $data_type_option.id
280            ))),
281        }
282    };
283    ($data_type_option:ident, $data_value:ident, Uuid) => {
284        match $data_type_option.id {
285            ColType::Uuid | ColType::Timeuuid => as_res_opt!($data_value, decode_timeuuid),
286            _ => Err(Error::General(format!(
287                "Invalid conversion. \
288                 Cannot convert {:?} into Uuid (valid types: Uuid, Timeuuid).",
289                $data_type_option.id
290            ))),
291        }
292    };
293    ($data_type_option:ident, $data_value:ident, List) => {
294        match $data_type_option.id {
295            ColType::List | ColType::Set => match $data_value.as_slice() {
296                Some(ref bytes) => decode_list(bytes)
297                    .map(|data| Some(List::new(data, $data_type_option.clone())))
298                    .map_err(Into::into),
299                None => Ok(None),
300            },
301            _ => Err(Error::General(format!(
302                "Invalid conversion. \
303                 Cannot convert {:?} into List (valid types: List, Set).",
304                $data_type_option.id
305            ))),
306        }
307    };
308    ($data_type_option:ident, $data_value:ident, Map) => {
309        match $data_type_option.id {
310            ColType::Map => match $data_value.as_slice() {
311                Some(ref bytes) => decode_map(bytes)
312                    .map(|data| Some(Map::new(data, $data_type_option.clone())))
313                    .map_err(Into::into),
314                None => Ok(None),
315            },
316            _ => Err(Error::General(format!(
317                "Invalid conversion. \
318                 Cannot convert {:?} into Map (valid types: Map).",
319                $data_type_option.id
320            ))),
321        }
322    };
323    ($data_type_option:ident, $data_value:ident, UDT) => {
324        match *$data_type_option {
325            ColTypeOption {
326                id: ColType::Udt,
327                value: Some(ColTypeOptionValue::UdtType(ref list_type_option)),
328            } => match $data_value.as_slice() {
329                Some(ref bytes) => decode_udt(bytes, list_type_option.descriptions.len())
330                    .map(|data| Some(UDT::new(data, list_type_option)))
331                    .map_err(Into::into),
332                None => Ok(None),
333            },
334            _ => Err(Error::General(format!(
335                "Invalid conversion. \
336                 Cannot convert {:?} into UDT (valid types: UDT).",
337                $data_type_option.id
338            ))),
339        }
340    };
341    ($data_type_option:ident, $data_value:ident, Tuple) => {
342        match *$data_type_option {
343            ColTypeOption {
344                id: ColType::Tuple,
345                value: Some(ColTypeOptionValue::TupleType(ref list_type_option)),
346            } => match $data_value.as_slice() {
347                Some(ref bytes) => decode_tuple(bytes, list_type_option.types.len())
348                    .map(|data| Some(Tuple::new(data, list_type_option)))
349                    .map_err(Into::into),
350                None => Ok(None),
351            },
352            _ => Err(Error::General(format!(
353                "Invalid conversion. \
354                 Cannot convert {:?} into Tuple (valid types: tuple).",
355                $data_type_option.id
356            ))),
357        }
358    };
359    ($data_type_option:ident, $data_value:ident, Timespec) => {
360        match $data_type_option.id {
361            ColType::Timestamp => match $data_value.as_slice() {
362                Some(ref bytes) => decode_timestamp(bytes)
363                    .map(|ts| Some(Timespec::new(ts / 1_000, (ts % 1_000 * 1_000_000) as i32)))
364                    .map_err(Into::into),
365                None => Ok(None),
366            },
367            _ => Err(Error::General(format!(
368                "Invalid conversion. \
369                 Cannot convert {:?} into Timespec (valid types: Timestamp).",
370                $data_type_option.id
371            ))),
372        }
373    };
374    ($data_type_option:ident, $data_value:ident, Decimal) => {
375        match $data_type_option.id {
376            ColType::Decimal => match $data_value.as_slice() {
377                Some(ref bytes) => decode_decimal(bytes).map(|d| Some(d)).map_err(Into::into),
378                None => Ok(None),
379            },
380            _ => Err(Error::General(format!(
381                "Invalid conversion. \
382                 Cannot convert {:?} into Decimal (valid types: Decimal).",
383                $data_type_option.id
384            ))),
385        }
386    };
387}