cassandra_protocol/
macros.rs

1#[macro_export]
2
3/// Transforms arguments to values consumed by queries.
4macro_rules! query_values {
5    ($($value:expr),*) => {
6        {
7            use cassandra_protocol::types::value::Value;
8            use cassandra_protocol::query::QueryValues;
9            let mut values: Vec<Value> = Vec::new();
10            $(
11                values.push($value.into());
12            )*
13            QueryValues::SimpleValues(values)
14        }
15    };
16    ($($name:expr => $value:expr),*) => {
17        {
18            use cassandra_protocol::types::value::Value;
19            use cassandra_protocol::query::QueryValues;
20            use std::collections::HashMap;
21            let mut values: HashMap<String, Value> = HashMap::new();
22            $(
23                values.insert($name.to_string(), $value.into());
24            )*
25            QueryValues::NamedValues(values)
26        }
27    };
28}
29
30macro_rules! vector_as_rust {
31    (f32) => {
32        impl AsRustType<Vec<f32>> for Vector {
33            fn as_rust_type(&self) -> Result<Option<Vec<f32>>> {
34                let mut result: Vec<f32> = Vec::new();
35                for data_value in &self.data {
36                    let float = decode_float(data_value.as_slice().unwrap_or(Err(
37                        Error::General(format!("Failed to convert {:?} into float", data_value)),
38                    )?))?;
39                    result.push(float);
40                }
41
42                Ok(Some(result))
43            }
44        }
45    };
46}
47
48macro_rules! list_as_rust {
49    (List) => (
50        impl AsRustType<Vec<List>> for List {
51            fn as_rust_type(&self) -> Result<Option<Vec<List>>> {
52                match self.metadata.value {
53                    Some(ColTypeOptionValue::CList(ref type_option)) |
54                    Some(ColTypeOptionValue::CSet(ref type_option)) => {
55                        let type_option_ref = type_option.as_ref();
56                        let protocol_version = self.protocol_version;
57                        let convert = self
58                            .map(|bytes| {
59                                as_rust_type!(type_option_ref, bytes, protocol_version, List)
60                                    .unwrap()
61                                    // item in a list supposed to be a non-null value.
62                                    // TODO: check if it's true
63                                    .unwrap()
64                            });
65
66                        Ok(Some(convert))
67                    },
68                    _ => Err(Error::General(format!("Invalid conversion. \
69                            Cannot convert {:?} into List (valid types: List, Set).",
70                            self.metadata.value)))
71                }
72            }
73        }
74    );
75    (Map) => (
76        impl AsRustType<Vec<Map>> for List {
77            fn as_rust_type(&self) -> Result<Option<Vec<Map>>> {
78                match self.metadata.value {
79                    Some(ColTypeOptionValue::CList(ref type_option)) |
80                    Some(ColTypeOptionValue::CSet(ref type_option)) => {
81                        let type_option_ref = type_option.as_ref();
82                        let protocol_version = self.protocol_version;
83                        let convert = self
84                            .map(|bytes| {
85                                as_rust_type!(type_option_ref, bytes, protocol_version, Map)
86                                    .unwrap()
87                                    // item in a list supposed to be a non-null value.
88                                    // TODO: check if it's true
89                                    .unwrap()
90                            });
91
92                        Ok(Some(convert))
93                    },
94                    _ => Err(Error::General(format!("Invalid conversion. \
95                            Cannot convert {:?} into List (valid types: List, Set).",
96                            self.metadata.value)))
97                }
98            }
99        }
100    );
101    (Udt) => (
102        impl AsRustType<Vec<Udt>> for List {
103            fn as_rust_type(&self) -> Result<Option<Vec<Udt>>> {
104                match self.metadata.value {
105                    Some(ColTypeOptionValue::CList(ref type_option)) |
106                    Some(ColTypeOptionValue::CSet(ref type_option)) => {
107                        let type_option_ref = type_option.as_ref();
108                        let protocol_version = self.protocol_version;
109                        let convert = self
110                            .map(|bytes| {
111                                as_rust_type!(type_option_ref, bytes, protocol_version, Udt)
112                                    .unwrap()
113                                    // item in a list supposed to be a non-null value.
114                                    // TODO: check if it's true
115                                    .unwrap()
116                            });
117
118                        Ok(Some(convert))
119                    },
120                    _ => Err(Error::General(format!("Invalid conversion. \
121                            Cannot convert {:?} into List (valid types: List, Set).",
122                            self.metadata.value)))
123                }
124            }
125        }
126    );
127    (Tuple) => (
128        impl AsRustType<Vec<Tuple>> for List {
129            fn as_rust_type(&self) -> Result<Option<Vec<Tuple>>> {
130                match self.metadata.value {
131                    Some(ColTypeOptionValue::CList(ref type_option)) |
132                    Some(ColTypeOptionValue::CSet(ref type_option)) => {
133                        let type_option_ref = type_option.as_ref();
134                        let protocol_version = self.protocol_version;
135                        let convert = self
136                            .map(|bytes| {
137                                as_rust_type!(type_option_ref, bytes, protocol_version, Tuple)
138                                    .unwrap()
139                                    // item in a list supposed to be a non-null value.
140                                    // TODO: check if it's true
141                                    .unwrap()
142                            });
143
144                        Ok(Some(convert))
145                    },
146                    _ => Err(Error::General(format!("Invalid conversion. \
147                            Cannot convert {:?} into List (valid types: List, Set).",
148                            self.metadata.value)))
149                }
150            }
151        }
152    );
153    ($($into_type:tt)+) => (
154        impl AsRustType<Vec<$($into_type)+>> for List {
155            fn as_rust_type(&self) -> Result<Option<Vec<$($into_type)+>>> {
156                match self.metadata.value {
157                    Some(ColTypeOptionValue::CList(ref type_option)) |
158                    Some(ColTypeOptionValue::CSet(ref type_option)) => {
159                        let type_option_ref = type_option.as_ref();
160                        let convert = self
161                            .map(|bytes| {
162                                as_rust_type!(type_option_ref, bytes, $($into_type)+)
163                                    .unwrap()
164                                    // item in a list supposed to be a non-null value.
165                                    // TODO: check if it's true
166                                    .unwrap()
167                            });
168
169                        Ok(Some(convert))
170                    },
171                    _ => Err(Error::General(format!("Invalid conversion. \
172                            Cannot convert {:?} into List (valid types: List, Set).",
173                            self.metadata.value)))
174                }
175            }
176        }
177    );
178}
179
180macro_rules! list_as_cassandra_type {
181    () => {
182        impl crate::types::AsCassandraType for List {
183            fn as_cassandra_type(
184                &self,
185            ) -> Result<Option<crate::types::cassandra_type::CassandraType>> {
186                use crate::error::Error;
187                use crate::types::cassandra_type::wrapper_fn;
188                use crate::types::cassandra_type::CassandraType;
189                use std::ops::Deref;
190
191                let protocol_version = self.protocol_version;
192
193                match self.metadata.value {
194                    Some(ColTypeOptionValue::CList(ref type_option))
195                    | Some(ColTypeOptionValue::CSet(ref type_option)) => {
196                        let type_option_ref = type_option.deref().clone();
197                        let wrapper = wrapper_fn(&type_option_ref.id);
198                        let convert = self
199                            .try_map(|bytes| wrapper(bytes, &type_option_ref, protocol_version));
200
201                        convert.map(|convert| Some(CassandraType::List(convert)))
202                    }
203                    _ => Err(Error::General(format!(
204                        "Invalid conversion. \
205                            Cannot convert {:?} into List (valid types: List, Set).",
206                        self.metadata.value
207                    ))),
208                }
209            }
210        }
211    };
212}
213
214macro_rules! vector_as_cassandra_type {
215    () => {
216        impl crate::types::AsCassandraType for Vector {
217            fn as_cassandra_type(
218                &self,
219            ) -> Result<Option<crate::types::cassandra_type::CassandraType>> {
220                use crate::error::Error;
221                use crate::types::cassandra_type::wrapper_fn;
222                use crate::types::cassandra_type::CassandraType;
223
224                let protocol_version = self.protocol_version;
225
226                match &self.metadata {
227                    ColTypeOption {
228                        id: ColType::Custom,
229                        value,
230                    } => {
231                        if let Some(value) = value {
232                            let VectorInfo { internal_type, .. } = get_vector_type_info(value)?;
233
234                            if internal_type == "FloatType" {
235                                let internal_type_option = ColTypeOption {
236                                    id: ColType::Float,
237                                    value: None,
238                                };
239
240                                let wrapper = wrapper_fn(&ColType::Float);
241
242                                let convert = self.try_map(|bytes| {
243                                    wrapper(bytes, &internal_type_option, protocol_version)
244                                });
245
246                                return convert.map(|convert| Some(CassandraType::Vector(convert)));
247                            } else {
248                                return Err(Error::General(format!(
249                                    "Invalid conversion. \
250            Cannot convert Vector<{:?}> into Vector (valid types: Vector<FloatType>",
251                                    internal_type
252                                )));
253                            }
254                        } else {
255                            return Err(Error::General("Custom type string is none".to_string()));
256                        }
257                    }
258                    _ => Err(Error::General(format!(
259                        "Invalid conversion. \
260                            Cannot convert {:?} into Vector (valid types: Custom).",
261                        self.metadata.value
262                    ))),
263                }
264            }
265        }
266    };
267}
268
269macro_rules! map_as_cassandra_type {
270    () => {
271        impl crate::types::AsCassandraType for Map {
272            fn as_cassandra_type(
273                &self,
274            ) -> Result<Option<crate::types::cassandra_type::CassandraType>> {
275                use crate::types::cassandra_type::wrapper_fn;
276                use crate::types::cassandra_type::CassandraType;
277                use itertools::Itertools;
278                use std::ops::Deref;
279
280                if let Some(ColTypeOptionValue::CMap(
281                    ref key_col_type_option,
282                    ref value_col_type_option,
283                )) = self.metadata.value
284                {
285                    let key_col_type_option = key_col_type_option.deref().clone();
286                    let value_col_type_option = value_col_type_option.deref().clone();
287
288                    let key_wrapper = wrapper_fn(&key_col_type_option.id);
289
290                    let value_wrapper = wrapper_fn(&value_col_type_option.id);
291
292                    let protocol_version = self.protocol_version;
293
294                    return self
295                        .data
296                        .iter()
297                        .map(|(key, value)| {
298                            key_wrapper(key, &key_col_type_option, protocol_version).and_then(
299                                |key| {
300                                    value_wrapper(value, &value_col_type_option, protocol_version)
301                                        .map(|value| (key, value))
302                                },
303                            )
304                        })
305                        .try_collect()
306                        .map(|map| Some(CassandraType::Map(map)));
307                } else {
308                    panic!("not a map")
309                }
310            }
311        }
312    };
313}
314
315macro_rules! tuple_as_cassandra_type {
316    () => {
317        impl crate::types::AsCassandraType for Tuple {
318            fn as_cassandra_type(
319                &self,
320            ) -> Result<Option<crate::types::cassandra_type::CassandraType>> {
321                use crate::types::cassandra_type::wrapper_fn;
322                use crate::types::cassandra_type::CassandraType;
323                use itertools::Itertools;
324
325                let protocol_version = self.protocol_version;
326                let values = self
327                    .data
328                    .iter()
329                    .map(|(col_type, bytes)| {
330                        let wrapper = wrapper_fn(&col_type.id);
331                        wrapper(&bytes, col_type, protocol_version)
332                    })
333                    .try_collect()?;
334
335                Ok(Some(CassandraType::Tuple(values)))
336            }
337        }
338    };
339}
340
341macro_rules! udt_as_cassandra_type {
342    () => {
343        impl crate::types::AsCassandraType for Udt {
344            fn as_cassandra_type(
345                &self,
346            ) -> Result<Option<crate::types::cassandra_type::CassandraType>> {
347                use crate::types::cassandra_type::wrapper_fn;
348                use crate::types::cassandra_type::CassandraType;
349                use std::collections::HashMap;
350
351                let mut map = HashMap::with_capacity(self.data.len());
352                let protocol_version = self.protocol_version;
353
354                for (key, (col_type, bytes)) in &self.data {
355                    let wrapper = wrapper_fn(&col_type.id);
356                    let value = wrapper(&bytes, col_type, protocol_version)?;
357                    map.insert(key.clone(), value);
358                }
359
360                Ok(Some(CassandraType::Udt(map)))
361            }
362        }
363    };
364}
365
366macro_rules! map_as_rust {
367    ({ Tuple }, { List }) => (
368        impl AsRustType<HashMap<Tuple, List>> for Map {
369            /// Converts `Map` into `HashMap` for blob values.
370            fn as_rust_type(&self) -> Result<Option<HashMap<Tuple, List>>> {
371                if let Some(ColTypeOptionValue::CMap(key_type_option, val_type_option)) = &self.metadata.value {
372                    let mut map = HashMap::with_capacity(self.data.len());
373                        let key_type_option = key_type_option.as_ref();
374                        let val_type_option = val_type_option.as_ref();
375                        let protocol_version = self.protocol_version;
376
377                        for (key, val) in self.data.iter() {
378                            let key = as_rust_type!(key_type_option, key, protocol_version, Tuple)?;
379                            let val = as_rust_type!(val_type_option, val, protocol_version, List)?;
380                            if let (Some(key), Some(val)) = (key, val) {
381                                map.insert(key, val);
382                            }
383                        }
384
385                        Ok(Some(map))
386                } else {
387                    Err(format!("Invalid column type for map: {:?}", self.metadata.value).into())
388                }
389            }
390        }
391    );
392    ({ Tuple }, { Map }) => (
393        impl AsRustType<HashMap<Tuple, Map>> for Map {
394            /// Converts `Map` into `HashMap` for blob values.
395            fn as_rust_type(&self) -> Result<Option<HashMap<Tuple, Map>>> {
396                if let Some(ColTypeOptionValue::CMap(key_type_option, val_type_option)) = &self.metadata.value {
397                    let mut map = HashMap::with_capacity(self.data.len());
398                        let key_type_option = key_type_option.as_ref();
399                        let val_type_option = val_type_option.as_ref();
400                        let protocol_version = self.protocol_version;
401
402                        for (key, val) in self.data.iter() {
403                            let key = as_rust_type!(key_type_option, key, protocol_version, Tuple)?;
404                            let val = as_rust_type!(val_type_option, val, protocol_version, Map)?;
405                            if let (Some(key), Some(val)) = (key, val) {
406                                map.insert(key, val);
407                            }
408                        }
409
410                        Ok(Some(map))
411                } else {
412                    Err(format!("Invalid column type for map: {:?}", self.metadata.value).into())
413                }
414            }
415        }
416    );
417    ({ Tuple }, { Udt }) => (
418        impl AsRustType<HashMap<Tuple, Udt>> for Map {
419            /// Converts `Map` into `HashMap` for blob values.
420            fn as_rust_type(&self) -> Result<Option<HashMap<Tuple, Udt>>> {
421                if let Some(ColTypeOptionValue::CMap(key_type_option, val_type_option)) = &self.metadata.value {
422                    let mut map = HashMap::with_capacity(self.data.len());
423                        let key_type_option = key_type_option.as_ref();
424                        let val_type_option = val_type_option.as_ref();
425                        let protocol_version = self.protocol_version;
426
427                        for (key, val) in self.data.iter() {
428                            let key = as_rust_type!(key_type_option, key, protocol_version, Tuple)?;
429                            let val = as_rust_type!(val_type_option, val, protocol_version, Udt)?;
430                            if let (Some(key), Some(val)) = (key, val) {
431                                map.insert(key, val);
432                            }
433                        }
434
435                        Ok(Some(map))
436                } else {
437                    Err(format!("Invalid column type for map: {:?}", self.metadata.value).into())
438                }
439            }
440        }
441    );
442    ({ Tuple }, { Tuple }) => (
443        impl AsRustType<HashMap<Tuple, Tuple>> for Map {
444            /// Converts `Map` into `HashMap` for blob values.
445            fn as_rust_type(&self) -> Result<Option<HashMap<Tuple, Tuple>>> {
446                if let Some(ColTypeOptionValue::CMap(key_type_option, val_type_option)) = &self.metadata.value {
447                    let mut map = HashMap::with_capacity(self.data.len());
448                        let key_type_option = key_type_option.as_ref();
449                        let val_type_option = val_type_option.as_ref();
450                        let protocol_version = self.protocol_version;
451
452                        for (key, val) in self.data.iter() {
453                            let key = as_rust_type!(key_type_option, key, protocol_version, Tuple)?;
454                            let val = as_rust_type!(val_type_option, val, protocol_version, Tuple)?;
455                            if let (Some(key), Some(val)) = (key, val) {
456                                map.insert(key, val);
457                            }
458                        }
459
460                        Ok(Some(map))
461                } else {
462                    Err(format!("Invalid column type for map: {:?}", self.metadata.value).into())
463                }
464            }
465        }
466    );
467    ({ Tuple }, { $($val_type:tt)+ }) => (
468        impl AsRustType<HashMap<Tuple, $($val_type)+>> for Map {
469            /// Converts `Map` into `HashMap` for blob values.
470            fn as_rust_type(&self) -> Result<Option<HashMap<Tuple, $($val_type)+>>> {
471                if let Some(ColTypeOptionValue::CMap(key_type_option, val_type_option)) = &self.metadata.value {
472                    let mut map = HashMap::with_capacity(self.data.len());
473                        let key_type_option = key_type_option.as_ref();
474                        let val_type_option = val_type_option.as_ref();
475                        let protocol_version = self.protocol_version;
476
477                        for (key, val) in self.data.iter() {
478                            let key = as_rust_type!(key_type_option, key, protocol_version, Tuple)?;
479                            let val = as_rust_type!(val_type_option, val, $($val_type)+)?;
480                            if let (Some(key), Some(val)) = (key, val) {
481                                map.insert(key, val);
482                            }
483                        }
484
485                        Ok(Some(map))
486                } else {
487                    Err(format!("Invalid column type for map: {:?}", self.metadata.value).into())
488                }
489            }
490        }
491    );
492    ({ $($key_type:tt)+ }, { List }) => (
493        impl AsRustType<HashMap<$($key_type)+, List>> for Map {
494            /// Converts `Map` into `HashMap` for blob values.
495            fn as_rust_type(&self) -> Result<Option<HashMap<$($key_type)+, List>>> {
496                if let Some(ColTypeOptionValue::CMap(key_type_option, val_type_option)) = &self.metadata.value {
497                    let mut map = HashMap::with_capacity(self.data.len());
498                        let key_type_option = key_type_option.as_ref();
499                        let val_type_option = val_type_option.as_ref();
500                        let protocol_version = self.protocol_version;
501
502                        for (key, val) in self.data.iter() {
503                            let key = as_rust_type!(key_type_option, key, $($key_type)+)?;
504                            let val = as_rust_type!(val_type_option, val, protocol_version, List)?;
505                            if let (Some(key), Some(val)) = (key, val) {
506                                map.insert(key, val);
507                            }
508                        }
509
510                        Ok(Some(map))
511                } else {
512                    Err(format!("Invalid column type for map: {:?}", self.metadata.value).into())
513                }
514            }
515        }
516    );
517    ({ $($key_type:tt)+ }, { Map }) => (
518        impl AsRustType<HashMap<$($key_type)+, Map>> for Map {
519            /// Converts `Map` into `HashMap` for blob values.
520            fn as_rust_type(&self) -> Result<Option<HashMap<$($key_type)+, Map>>> {
521                if let Some(ColTypeOptionValue::CMap(key_type_option, val_type_option)) = &self.metadata.value {
522                    let mut map = HashMap::with_capacity(self.data.len());
523                        let key_type_option = key_type_option.as_ref();
524                        let val_type_option = val_type_option.as_ref();
525                        let protocol_version = self.protocol_version;
526
527                        for (key, val) in self.data.iter() {
528                            let key = as_rust_type!(key_type_option, key, $($key_type)+)?;
529                            let val = as_rust_type!(val_type_option, val, protocol_version, Map)?;
530                            if let (Some(key), Some(val)) = (key, val) {
531                                map.insert(key, val);
532                            }
533                        }
534
535                        Ok(Some(map))
536                } else {
537                    Err(format!("Invalid column type for map: {:?}", self.metadata.value).into())
538                }
539            }
540        }
541    );
542    ({ $($key_type:tt)+ }, { Udt }) => (
543        impl AsRustType<HashMap<$($key_type)+, Udt>> for Map {
544            /// Converts `Map` into `HashMap` for blob values.
545            fn as_rust_type(&self) -> Result<Option<HashMap<$($key_type)+, Udt>>> {
546                if let Some(ColTypeOptionValue::CMap(key_type_option, val_type_option)) = &self.metadata.value {
547                    let mut map = HashMap::with_capacity(self.data.len());
548                        let key_type_option = key_type_option.as_ref();
549                        let val_type_option = val_type_option.as_ref();
550                        let protocol_version = self.protocol_version;
551
552                        for (key, val) in self.data.iter() {
553                            let key = as_rust_type!(key_type_option, key, $($key_type)+)?;
554                            let val = as_rust_type!(val_type_option, val, protocol_version, Udt)?;
555                            if let (Some(key), Some(val)) = (key, val) {
556                                map.insert(key, val);
557                            }
558                        }
559
560                        Ok(Some(map))
561                } else {
562                    Err(format!("Invalid column type for map: {:?}", self.metadata.value).into())
563                }
564            }
565        }
566    );
567    ({ $($key_type:tt)+ }, { Tuple }) => (
568        impl AsRustType<HashMap<$($key_type)+, Tuple>> for Map {
569            /// Converts `Map` into `HashMap` for blob values.
570            fn as_rust_type(&self) -> Result<Option<HashMap<$($key_type)+, Tuple>>> {
571                if let Some(ColTypeOptionValue::CMap(key_type_option, val_type_option)) = &self.metadata.value {
572                    let mut map = HashMap::with_capacity(self.data.len());
573                        let key_type_option = key_type_option.as_ref();
574                        let val_type_option = val_type_option.as_ref();
575                        let protocol_version = self.protocol_version;
576
577                        for (key, val) in self.data.iter() {
578                            let key = as_rust_type!(key_type_option, key, $($key_type)+)?;
579                            let val = as_rust_type!(val_type_option, val, protocol_version, Tuple)?;
580                            if let (Some(key), Some(val)) = (key, val) {
581                                map.insert(key, val);
582                            }
583                        }
584
585                        Ok(Some(map))
586                } else {
587                    Err(format!("Invalid column type for map: {:?}", self.metadata.value).into())
588                }
589            }
590        }
591    );
592    ({ $($key_type:tt)+ }, { $($val_type:tt)+ }) => (
593        impl AsRustType<HashMap<$($key_type)+, $($val_type)+>> for Map {
594            /// Converts `Map` into `HashMap` for blob values.
595            fn as_rust_type(&self) -> Result<Option<HashMap<$($key_type)+, $($val_type)+>>> {
596                if let Some(ColTypeOptionValue::CMap(key_type_option, val_type_option)) = &self.metadata.value {
597                    let mut map = HashMap::with_capacity(self.data.len());
598                        let key_type_option = key_type_option.as_ref();
599                        let val_type_option = val_type_option.as_ref();
600
601                        for (key, val) in self.data.iter() {
602                            let key = as_rust_type!(key_type_option, key, $($key_type)+)?;
603                            let val = as_rust_type!(val_type_option, val, $($val_type)+)?;
604                            if let (Some(key), Some(val)) = (key, val) {
605                                map.insert(key, val);
606                            }
607                        }
608
609                        Ok(Some(map))
610                } else {
611                    Err(format!("Invalid column type for map: {:?}", self.metadata.value).into())
612                }
613            }
614        }
615    );
616}
617
618macro_rules! into_rust_by_name {
619    (Row, List) => (
620        impl IntoRustByName<List> for Row {
621            fn get_by_name(&self, name: &str) -> Result<Option<List>> {
622                let protocol_version = self.protocol_version;
623                self.col_spec_by_name(name)
624                    .ok_or(column_is_empty_err(name))
625                    .and_then(|(col_spec, cbytes)| {
626                        let col_type = &col_spec.col_type;
627                        as_rust_type!(col_type, cbytes, protocol_version, List)
628                    })
629            }
630        }
631    );
632    (Row, Vector) => (
633        impl IntoRustByName<Vector> for Row {
634            fn get_by_name(&self, name: &str) -> Result<Option<Vector>> {
635                let protocol_version = self.protocol_version;
636                self.col_spec_by_name(name)
637                    .ok_or(column_is_empty_err(name))
638                    .and_then(|(col_spec, cbytes)| {
639                        let col_type = &col_spec.col_type;
640                        as_rust_type!(col_type, cbytes, protocol_version, Vector)
641                    })
642            }
643        }
644    );
645    (Row, Map) => (
646        impl IntoRustByName<Map> for Row {
647            fn get_by_name(&self, name: &str) -> Result<Option<Map>> {
648                let protocol_version = self.protocol_version;
649                self.col_spec_by_name(name)
650                    .ok_or(column_is_empty_err(name))
651                    .and_then(|(col_spec, cbytes)| {
652                        let col_type = &col_spec.col_type;
653                        as_rust_type!(col_type, cbytes, protocol_version, Map)
654                    })
655            }
656        }
657    );
658    (Row, Udt) => (
659        impl IntoRustByName<Udt> for Row {
660            fn get_by_name(&self, name: &str) -> Result<Option<Udt>> {
661                let protocol_version = self.protocol_version;
662                self.col_spec_by_name(name)
663                    .ok_or(column_is_empty_err(name))
664                    .and_then(|(col_spec, cbytes)| {
665                        let col_type = &col_spec.col_type;
666                        as_rust_type!(col_type, cbytes, protocol_version, Udt)
667                    })
668            }
669        }
670    );
671    (Row, Tuple) => (
672        impl IntoRustByName<Tuple> for Row {
673            fn get_by_name(&self, name: &str) -> Result<Option<Tuple>> {
674                let protocol_version = self.protocol_version;
675                self.col_spec_by_name(name)
676                    .ok_or(column_is_empty_err(name))
677                    .and_then(|(col_spec, cbytes)| {
678                        let col_type = &col_spec.col_type;
679                        as_rust_type!(col_type, cbytes, protocol_version, Tuple)
680                    })
681            }
682        }
683    );
684    (Row, $($into_type:tt)+) => (
685        impl IntoRustByName<$($into_type)+> for Row {
686            fn get_by_name(&self, name: &str) -> Result<Option<$($into_type)+>> {
687                self.col_spec_by_name(name)
688                    .ok_or(column_is_empty_err(name))
689                    .and_then(|(col_spec, cbytes)| {
690                        let col_type = &col_spec.col_type;
691                        as_rust_type!(col_type, cbytes, $($into_type)+)
692                    })
693            }
694        }
695    );
696    (Udt, List) => (
697        impl IntoRustByName<List> for Udt {
698            fn get_by_name(&self, name: &str) -> Result<Option<List>> {
699                let protocol_version = self.protocol_version;
700                self.data.get(name)
701                    .ok_or(column_is_empty_err(name))
702                    .and_then(|v| {
703                        let &(ref col_type, ref bytes) = v;
704                        let converted = as_rust_type!(col_type, bytes, protocol_version, List);
705                        converted.map_err(|err| err.into())
706                    })
707            }
708        }
709    );
710    (Udt, Map) => (
711        impl IntoRustByName<Map> for Udt {
712            fn get_by_name(&self, name: &str) -> Result<Option<Map>> {
713                let protocol_version = self.protocol_version;
714                self.data.get(name)
715                    .ok_or(column_is_empty_err(name))
716                    .and_then(|v| {
717                        let &(ref col_type, ref bytes) = v;
718                        let converted = as_rust_type!(col_type, bytes, protocol_version, Map);
719                        converted.map_err(|err| err.into())
720                    })
721            }
722        }
723    );
724    (Udt, Udt) => (
725        impl IntoRustByName<Udt> for Udt {
726            fn get_by_name(&self, name: &str) -> Result<Option<Udt>> {
727                let protocol_version = self.protocol_version;
728                self.data.get(name)
729                    .ok_or(column_is_empty_err(name))
730                    .and_then(|v| {
731                        let &(ref col_type, ref bytes) = v;
732                        let converted = as_rust_type!(col_type, bytes, protocol_version, Udt);
733                        converted.map_err(|err| err.into())
734                    })
735            }
736        }
737    );
738    (Udt, Tuple) => (
739        impl IntoRustByName<Tuple> for Udt {
740            fn get_by_name(&self, name: &str) -> Result<Option<Tuple>> {
741                let protocol_version = self.protocol_version;
742                self.data.get(name)
743                    .ok_or(column_is_empty_err(name))
744                    .and_then(|v| {
745                        let &(ref col_type, ref bytes) = v;
746                        let converted = as_rust_type!(col_type, bytes, protocol_version, Tuple);
747                        converted.map_err(|err| err.into())
748                    })
749            }
750        }
751    );
752    (Udt, $($into_type:tt)+) => (
753        impl IntoRustByName<$($into_type)+> for Udt {
754            fn get_by_name(&self, name: &str) -> Result<Option<$($into_type)+>> {
755                self.data.get(name)
756                    .ok_or(column_is_empty_err(name))
757                    .and_then(|v| {
758                        let &(ref col_type, ref bytes) = v;
759                        let converted = as_rust_type!(col_type, bytes, $($into_type)+);
760                        converted.map_err(|err| err.into())
761                    })
762            }
763        }
764    );
765}
766
767macro_rules! into_rust_by_index {
768    (Tuple, List) => (
769        impl IntoRustByIndex<List> for Tuple {
770            fn get_by_index(&self, index: usize) -> Result<Option<List>> {
771                let protocol_version = self.protocol_version;
772                self.data
773                    .get(index)
774                    .ok_or(column_is_empty_err(index))
775                    .and_then(|v| {
776                        let &(ref col_type, ref bytes) = v;
777                        let converted = as_rust_type!(col_type, bytes, protocol_version, List);
778                        converted.map_err(|err| err.into())
779                    })
780            }
781        }
782    );
783    (Tuple, Map) => (
784        impl IntoRustByIndex<Map> for Tuple {
785            fn get_by_index(&self, index: usize) -> Result<Option<Map>> {
786                let protocol_version = self.protocol_version;
787                self.data
788                    .get(index)
789                    .ok_or(column_is_empty_err(index))
790                    .and_then(|v| {
791                        let &(ref col_type, ref bytes) = v;
792                        let converted = as_rust_type!(col_type, bytes, protocol_version, Map);
793                        converted.map_err(|err| err.into())
794                    })
795            }
796        }
797    );
798    (Tuple, Udt) => (
799        impl IntoRustByIndex<Udt> for Tuple {
800            fn get_by_index(&self, index: usize) -> Result<Option<Udt>> {
801                let protocol_version = self.protocol_version;
802                self.data
803                    .get(index)
804                    .ok_or(column_is_empty_err(index))
805                    .and_then(|v| {
806                        let &(ref col_type, ref bytes) = v;
807                        let converted = as_rust_type!(col_type, bytes, protocol_version, Udt);
808                        converted.map_err(|err| err.into())
809                    })
810            }
811        }
812    );
813    (Tuple, Tuple) => (
814        impl IntoRustByIndex<Tuple> for Tuple {
815            fn get_by_index(&self, index: usize) -> Result<Option<Tuple>> {
816                let protocol_version = self.protocol_version;
817                self.data
818                    .get(index)
819                    .ok_or(column_is_empty_err(index))
820                    .and_then(|v| {
821                        let &(ref col_type, ref bytes) = v;
822                        let converted = as_rust_type!(col_type, bytes, protocol_version, Tuple);
823                        converted.map_err(|err| err.into())
824                    })
825            }
826        }
827    );
828    (Tuple, $($into_type:tt)+) => (
829        impl IntoRustByIndex<$($into_type)+> for Tuple {
830            fn get_by_index(&self, index: usize) -> Result<Option<$($into_type)+>> {
831                self.data
832                    .get(index)
833                    .ok_or(column_is_empty_err(index))
834                    .and_then(|v| {
835                        let &(ref col_type, ref bytes) = v;
836                        let converted = as_rust_type!(col_type, bytes, $($into_type)+);
837                        converted.map_err(|err| err.into())
838                    })
839            }
840        }
841    );
842    (Row, List) => (
843        impl IntoRustByIndex<List> for Row {
844            fn get_by_index(&self, index: usize) -> Result<Option<List>> {
845                let protocol_version = self.protocol_version;
846                self.col_spec_by_index(index)
847                    .ok_or(column_is_empty_err(index))
848                    .and_then(|(col_spec, cbytes)| {
849                        let col_type = &col_spec.col_type;
850                        as_rust_type!(col_type, cbytes, protocol_version, List)
851                    })
852            }
853        }
854    );
855    (Row, Map) => (
856        impl IntoRustByIndex<Map> for Row {
857            fn get_by_index(&self, index: usize) -> Result<Option<Map>> {
858                let protocol_version = self.protocol_version;
859                self.col_spec_by_index(index)
860                    .ok_or(column_is_empty_err(index))
861                    .and_then(|(col_spec, cbytes)| {
862                        let col_type = &col_spec.col_type;
863                        as_rust_type!(col_type, cbytes, protocol_version, Map)
864                    })
865            }
866        }
867    );
868    (Row, Udt) => (
869        impl IntoRustByIndex<Udt> for Row {
870            fn get_by_index(&self, index: usize) -> Result<Option<Udt>> {
871                let protocol_version = self.protocol_version;
872                self.col_spec_by_index(index)
873                    .ok_or(column_is_empty_err(index))
874                    .and_then(|(col_spec, cbytes)| {
875                        let col_type = &col_spec.col_type;
876                        as_rust_type!(col_type, cbytes, protocol_version, Udt)
877                    })
878            }
879        }
880    );
881    (Row, Tuple) => (
882        impl IntoRustByIndex<Tuple> for Row {
883            fn get_by_index(&self, index: usize) -> Result<Option<Tuple>> {
884                let protocol_version = self.protocol_version;
885                self.col_spec_by_index(index)
886                    .ok_or(column_is_empty_err(index))
887                    .and_then(|(col_spec, cbytes)| {
888                        let col_type = &col_spec.col_type;
889                        as_rust_type!(col_type, cbytes, protocol_version, Tuple)
890                    })
891            }
892        }
893    );
894    (Row, $($into_type:tt)+) => (
895        impl IntoRustByIndex<$($into_type)+> for Row {
896            fn get_by_index(&self, index: usize) -> Result<Option<$($into_type)+>> {
897                self.col_spec_by_index(index)
898                    .ok_or(column_is_empty_err(index))
899                    .and_then(|(col_spec, cbytes)| {
900                        let col_type = &col_spec.col_type;
901                        as_rust_type!(col_type, cbytes, $($into_type)+)
902                    })
903            }
904        }
905    );
906}
907
908macro_rules! as_res_opt {
909    ($data_value:ident, $deserialize:expr) => {
910        match $data_value.as_slice() {
911            Some(ref bytes) => ($deserialize)(bytes).map(Some).map_err(Into::into),
912            None => Ok(None),
913        }
914    };
915}
916
917/// Decodes any Cassandra data type into the corresponding Rust type,
918/// given the column type as `ColTypeOption` and the value as `CBytes`
919/// plus the matching Rust type.
920macro_rules! as_rust_type {
921    ($data_type_option:ident, $data_value:ident, Blob) => {
922
923        match $data_type_option.id {
924            ColType::Blob => as_res_opt!($data_value, decode_blob),
925            ColType::Custom => {
926                let unmarshal = || {
927                    if let Some(crate::frame::message_result::ColTypeOptionValue::CString(value)) = &$data_type_option.value {
928                        if value.as_str() == "org.apache.cassandra.db.marshal.BytesType" {
929                            return as_res_opt!($data_value, decode_blob);
930                        }
931                    }
932
933                    Err(crate::error::Error::General(format!(
934                        "Invalid conversion. \
935                         Cannot convert marshaled type {:?} into Vec<u8> (valid types: org.apache.cassandra.db.marshal.BytesType).",
936                        $data_type_option
937                    )))
938                };
939
940                unmarshal()
941            }
942            _ => Err(crate::error::Error::General(format!(
943                "Invalid conversion. \
944                 Cannot convert {:?} into Vec<u8> (valid types: Blob).",
945                $data_type_option.id
946            ))),
947        }
948    };
949    ($data_type_option:ident, $data_value:ident, String) => {
950        match $data_type_option.id {
951            ColType::Custom => as_res_opt!($data_value, decode_custom),
952            ColType::Ascii => as_res_opt!($data_value, decode_ascii),
953            ColType::Varchar => as_res_opt!($data_value, decode_varchar),
954            // TODO: clarify when to use decode_text.
955            // it's not mentioned in
956            // https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L582
957            // ColType::XXX => decode_text($data_value)?
958            _ => Err(crate::error::Error::General(format!(
959                "Invalid conversion. \
960                 Cannot convert {:?} into String (valid types: Custom, Ascii, Varchar).",
961                $data_type_option.id
962            ))),
963        }
964    };
965    ($data_type_option:ident, $data_value:ident, bool) => {
966        match $data_type_option.id {
967            ColType::Boolean => as_res_opt!($data_value, decode_boolean),
968            ColType::Custom => {
969                let unmarshal = || {
970                    if let Some(ColTypeOptionValue::CString(value)) = &$data_type_option.value {
971                        if value.as_str() == "org.apache.cassandra.db.marshal.BooleanType" {
972                            return as_res_opt!($data_value, decode_boolean);
973                        }
974                    }
975
976                    Err(crate::error::Error::General(format!(
977                        "Invalid conversion. \
978                         Cannot convert marshaled type {:?} into bool (valid types: org.apache.cassandra.db.marshal.BooleanType).",
979                        $data_type_option
980                    )))
981                };
982
983                unmarshal()
984            }
985            _ => Err(crate::error::Error::General(format!(
986                "Invalid conversion. \
987                 Cannot convert {:?} into bool (valid types: Boolean, Custom).",
988                $data_type_option.id
989            ))),
990        }
991    };
992    ($data_type_option:ident, $data_value:ident, i64) => {
993        match $data_type_option.id {
994            ColType::Bigint => as_res_opt!($data_value, decode_bigint),
995            ColType::Timestamp => as_res_opt!($data_value, decode_timestamp),
996            ColType::Time => as_res_opt!($data_value, decode_time),
997            ColType::Counter => as_res_opt!($data_value, decode_bigint),
998            ColType::Custom => {
999                let unmarshal = || {
1000                    if let Some(ColTypeOptionValue::CString(value)) = &$data_type_option.value {
1001                        match value.as_str() {
1002                            "org.apache.cassandra.db.marshal.LongType" | "org.apache.cassandra.db.marshal.CounterColumnType" => return as_res_opt!($data_value, decode_bigint),
1003                            "org.apache.cassandra.db.marshal.TimestampType" => return as_res_opt!($data_value, decode_timestamp),
1004                            "org.apache.cassandra.db.marshal.TimeType" => return as_res_opt!($data_value, decode_time),
1005                            _ => {}
1006                        }
1007                    }
1008
1009                    Err(crate::error::Error::General(format!(
1010                        "Invalid conversion. \
1011                         Cannot convert marshaled type {:?} into i64 (valid types: org.apache.cassandra.db.marshal.{{LongType|IntegerType|CounterColumnType|TimestampType|TimeType}}).",
1012                        $data_type_option
1013                    )))
1014                };
1015
1016                unmarshal()
1017            }
1018            _ => Err(crate::error::Error::General(format!(
1019                "Invalid conversion. \
1020                 Cannot convert {:?} into i64 (valid types: Bigint, Timestamp, Time,\
1021                 Counter, Custom).",
1022                $data_type_option.id
1023            ))),
1024        }
1025    };
1026    ($data_type_option:ident, $data_value:ident, i32) => {
1027        match $data_type_option.id {
1028            ColType::Int => as_res_opt!($data_value, decode_int),
1029            ColType::Date => as_res_opt!($data_value, decode_date),
1030            ColType::Custom => {
1031                let unmarshal = || {
1032                    if let Some(crate::frame::message_result::ColTypeOptionValue::CString(value)) = &$data_type_option.value {
1033                        match value.as_str() {
1034                            "org.apache.cassandra.db.marshal.Int32Type" => return as_res_opt!($data_value, decode_int),
1035                            "org.apache.cassandra.db.marshal.SimpleDateType" => return as_res_opt!($data_value, decode_date),
1036                            _ => {}
1037                        }
1038                    }
1039
1040                    Err(crate::error::Error::General(format!(
1041                        "Invalid conversion. \
1042                         Cannot convert marshaled type {:?} into i32 (valid types: org.apache.cassandra.db.marshal.Int32Type).",
1043                        $data_type_option
1044                    )))
1045                };
1046
1047                unmarshal()
1048            }
1049            _ => Err(crate::error::Error::General(format!(
1050                "Invalid conversion. \
1051                 Cannot convert {:?} into i32 (valid types: Int, Date, Custom).",
1052                $data_type_option.id
1053            ))),
1054        }
1055    };
1056    ($data_type_option:ident, $data_value:ident, i16) => {
1057        match $data_type_option.id {
1058            ColType::Smallint => as_res_opt!($data_value, decode_smallint),
1059            ColType::Custom => {
1060                let unmarshal = || {
1061                    if let Some(ColTypeOptionValue::CString(value)) = &$data_type_option.value {
1062                        if value.as_str() == "org.apache.cassandra.db.marshal.ShortType" {
1063                            return as_res_opt!($data_value, decode_smallint);
1064                        }
1065                    }
1066
1067                    Err(crate::error::Error::General(format!(
1068                        "Invalid conversion. \
1069                         Cannot convert marshaled type {:?} into i16 (valid types: org.apache.cassandra.db.marshal.ShortType).",
1070                        $data_type_option
1071                    )))
1072                };
1073
1074                unmarshal()
1075            }
1076            _ => Err(crate::error::Error::General(format!(
1077                "Invalid conversion. \
1078                 Cannot convert {:?} into i16 (valid types: Smallint, Custom).",
1079                $data_type_option.id
1080            ))),
1081        }
1082    };
1083    ($data_type_option:ident, $data_value:ident, i8) => {
1084        match $data_type_option.id {
1085            ColType::Tinyint => as_res_opt!($data_value, decode_tinyint),
1086            ColType::Custom => {
1087                let unmarshal = || {
1088                    if let Some(ColTypeOptionValue::CString(value)) = &$data_type_option.value {
1089                        if value.as_str() == "org.apache.cassandra.db.marshal.ByteType" {
1090                            return as_res_opt!($data_value, decode_tinyint);
1091                        }
1092                    }
1093
1094                    Err(crate::error::Error::General(format!(
1095                        "Invalid conversion. \
1096                         Cannot convert marshaled type {:?} into i8 (valid types: org.apache.cassandra.db.marshal.ByteType).",
1097                        $data_type_option
1098                    )))
1099                };
1100
1101                unmarshal()
1102            }
1103            _ => Err(crate::error::Error::General(format!(
1104                "Invalid conversion. \
1105                 Cannot convert {:?} into i8 (valid types: Tinyint, Custom).",
1106                $data_type_option.id
1107            ))),
1108        }
1109    };
1110    ($data_type_option:ident, $data_value:ident, NonZeroI64) => {
1111        match $data_type_option.id {
1112            ColType::Bigint => {
1113                as_res_opt!($data_value, decode_bigint).map(|value| value.and_then(NonZeroI64::new))
1114            }
1115            ColType::Timestamp => as_res_opt!($data_value, decode_timestamp)
1116                .map(|value| value.and_then(NonZeroI64::new)),
1117            ColType::Time => {
1118                as_res_opt!($data_value, decode_time).map(|value| value.and_then(NonZeroI64::new))
1119            }
1120            ColType::Counter => {
1121                as_res_opt!($data_value, decode_bigint).map(|value| value.and_then(NonZeroI64::new))
1122            }
1123            ColType::Custom => {
1124                let unmarshal = || {
1125                    if let Some(ColTypeOptionValue::CString(value)) = &$data_type_option.value {
1126                        match value.as_str() {
1127                            "org.apache.cassandra.db.marshal.LongType" | "org.apache.cassandra.db.marshal.CounterColumnType" => return as_res_opt!($data_value, decode_bigint),
1128                            "org.apache.cassandra.db.marshal.TimestampType" => return as_res_opt!($data_value, decode_timestamp),
1129                            "org.apache.cassandra.db.marshal.TimeType" => return as_res_opt!($data_value, decode_time),
1130                            _ => {}
1131                        }
1132                    }
1133
1134                    Err(Error::General(format!(
1135                        "Invalid conversion. \
1136                         Cannot convert marshaled type {:?} into i64 (valid types: org.apache.cassandra.db.marshal.{{LongType|IntegerType|CounterColumnType|TimestampType|TimeType}}).",
1137                        $data_type_option
1138                    )))
1139                };
1140
1141                unmarshal().map(|value| value.and_then(NonZeroI64::new))
1142            }
1143            _ => Err(Error::General(format!(
1144                "Invalid conversion. \
1145                 Cannot convert {:?} into NonZeroI64 (valid types: Bigint, Timestamp, Time,\
1146                 Counter, Custom).",
1147                $data_type_option.id
1148            ))),
1149        }
1150    };
1151    ($data_type_option:ident, $data_value:ident, NonZeroI32) => {
1152        match $data_type_option.id {
1153            ColType::Int => {
1154                as_res_opt!($data_value, decode_int).map(|value| value.and_then(NonZeroI32::new))
1155            }
1156            ColType::Date => {
1157                as_res_opt!($data_value, decode_date).map(|value| value.and_then(NonZeroI32::new))
1158            }
1159            ColType::Custom => {
1160                let unmarshal = || {
1161                    if let Some(ColTypeOptionValue::CString(value)) = &$data_type_option.value {
1162                        match value.as_str() {
1163                            "org.apache.cassandra.db.marshal.Int32Type" => return as_res_opt!($data_value, decode_int),
1164                            "org.apache.cassandra.db.marshal.SimpleDateType" => return as_res_opt!($data_value, decode_date),
1165                            _ => {}
1166                        }
1167                    }
1168
1169                    Err(Error::General(format!(
1170                        "Invalid conversion. \
1171                         Cannot convert marshaled type {:?} into i32 (valid types: org.apache.cassandra.db.marshal.Int32Type).",
1172                        $data_type_option
1173                    )))
1174                };
1175
1176                unmarshal().map(|value| value.and_then(NonZeroI32::new))
1177            }
1178            _ => Err(Error::General(format!(
1179                "Invalid conversion. \
1180                 Cannot convert {:?} into NonZeroI32 (valid types: Int, Date, Custom).",
1181                $data_type_option.id
1182            ))),
1183        }
1184    };
1185    ($data_type_option:ident, $data_value:ident, NonZeroI16) => {
1186        match $data_type_option.id {
1187            ColType::Smallint => as_res_opt!($data_value, decode_smallint)
1188                .map(|value| value.and_then(NonZeroI16::new)),
1189            ColType::Custom => {
1190                let unmarshal = || {
1191                    if let Some(ColTypeOptionValue::CString(value)) = &$data_type_option.value {
1192                        if value.as_str() == "org.apache.cassandra.db.marshal.ShortType" {
1193                            return as_res_opt!($data_value, decode_smallint);
1194                        }
1195                    }
1196
1197                    Err(Error::General(format!(
1198                        "Invalid conversion. \
1199                         Cannot convert marshaled type {:?} into NonZeroI16 (valid types: org.apache.cassandra.db.marshal.ShortType).",
1200                        $data_type_option
1201                    )))
1202                };
1203
1204                unmarshal().map(|value| value.and_then(NonZeroI16::new))
1205            }
1206            _ => Err(Error::General(format!(
1207                "Invalid conversion. \
1208                 Cannot convert {:?} into NonZeroI16 (valid types: Smallint, Custom).",
1209                $data_type_option.id
1210            ))),
1211        }
1212    };
1213    ($data_type_option:ident, $data_value:ident, NonZeroI8) => {
1214        match $data_type_option.id {
1215            ColType::Tinyint => {
1216                as_res_opt!($data_value, decode_tinyint).map(|value| value.and_then(NonZeroI8::new))
1217            }
1218            ColType::Custom => {
1219                let unmarshal = || {
1220                    if let Some(ColTypeOptionValue::CString(value)) = &$data_type_option.value {
1221                        if value.as_str() == "org.apache.cassandra.db.marshal.ByteType" {
1222                            return as_res_opt!($data_value, decode_tinyint);
1223                        }
1224                    }
1225
1226                    Err(Error::General(format!(
1227                        "Invalid conversion. \
1228                         Cannot convert marshaled type {:?} into NonZeroI8 (valid types: org.apache.cassandra.db.marshal.ByteType).",
1229                        $data_type_option
1230                    )))
1231                };
1232
1233                unmarshal().map(|value| value.and_then(NonZeroI8::new))
1234            }
1235            _ => Err(Error::General(format!(
1236                "Invalid conversion. \
1237                 Cannot convert {:?} into NonZeroI8 (valid types: Tinyint, Custom).",
1238                $data_type_option.id
1239            ))),
1240        }
1241    };
1242    ($data_type_option:ident, $data_value:ident, f64) => {
1243        match $data_type_option.id {
1244            ColType::Double => as_res_opt!($data_value, decode_double),
1245            ColType::Custom => {
1246                let unmarshal = || {
1247                    if let Some(ColTypeOptionValue::CString(value)) = &$data_type_option.value {
1248                        if value.as_str() == "org.apache.cassandra.db.marshal.DoubleType" {
1249                            return as_res_opt!($data_value, decode_double);
1250                        }
1251                    }
1252
1253                    Err(crate::error::Error::General(format!(
1254                        "Invalid conversion. \
1255                         Cannot convert marshaled type {:?} into f64 (valid types: org.apache.cassandra.db.marshal.DoubleType).",
1256                        $data_type_option
1257                    )))
1258                };
1259
1260                unmarshal()
1261            }
1262            _ => Err(crate::error::Error::General(format!(
1263                "Invalid conversion. \
1264                 Cannot convert {:?} into f64 (valid types: Double, Custom).",
1265                $data_type_option.id
1266            ))),
1267        }
1268    };
1269    ($data_type_option:ident, $data_value:ident, f32) => {
1270        match $data_type_option.id {
1271            ColType::Float => as_res_opt!($data_value, decode_float),
1272            ColType::Custom => {
1273                let unmarshal = || {
1274                    if let Some(ColTypeOptionValue::CString(value)) = &$data_type_option.value {
1275                        if value.as_str() == "org.apache.cassandra.db.marshal.FloatType" {
1276                            return as_res_opt!($data_value, decode_float);
1277                        }
1278                    }
1279
1280                    Err(crate::error::Error::General(format!(
1281                        "Invalid conversion. \
1282                         Cannot convert marshaled type {:?} into f32 (valid types: org.apache.cassandra.db.marshal.FloatType).",
1283                        $data_type_option
1284                    )))
1285                };
1286
1287                unmarshal()
1288            }
1289            _ => Err(crate::error::Error::General(format!(
1290                "Invalid conversion. \
1291                 Cannot convert {:?} into f32 (valid types: Float, Custom).",
1292                $data_type_option.id
1293            ))),
1294        }
1295    };
1296    ($data_type_option:ident, $data_value:ident, IpAddr) => {
1297        match $data_type_option.id {
1298            ColType::Inet => as_res_opt!($data_value, decode_inet),
1299            ColType::Custom => {
1300                let unmarshal = || {
1301                    if let Some(ColTypeOptionValue::CString(value)) = &$data_type_option.value {
1302                        if value.as_str() == "org.apache.cassandra.db.marshal.InetAddressType" {
1303                            return as_res_opt!($data_value, decode_inet);
1304                        }
1305                    }
1306
1307                    Err(crate::error::Error::General(format!(
1308                        "Invalid conversion. \
1309                         Cannot convert marshaled type {:?} into IpAddr (valid types: org.apache.cassandra.db.marshal.InetAddressType).",
1310                        $data_type_option
1311                    )))
1312                };
1313
1314                unmarshal()
1315            }
1316            _ => Err(crate::error::Error::General(format!(
1317                "Invalid conversion. \
1318                 Cannot convert {:?} into IpAddr (valid types: Inet, Custom).",
1319                $data_type_option.id
1320            ))),
1321        }
1322    };
1323    ($data_type_option:ident, $data_value:ident, Uuid) => {
1324        match $data_type_option.id {
1325            ColType::Uuid | ColType::Timeuuid => as_res_opt!($data_value, decode_timeuuid),
1326            ColType::Custom => {
1327                let unmarshal = || {
1328                    if let Some(ColTypeOptionValue::CString(value)) = &$data_type_option.value {
1329                        match value.as_str() {
1330                            "org.apache.cassandra.db.marshal.UUIDType" | "org.apache.cassandra.db.marshal.TimeUUIDType" => return as_res_opt!($data_value, decode_timeuuid),
1331                            _ => {}
1332                        }
1333                    }
1334
1335                    Err(crate::error::Error::General(format!(
1336                        "Invalid conversion. \
1337                         Cannot convert marshaled type {:?} into Uuid (valid types: org.apache.cassandra.db.marshal.{{UUIDType|TimeUUIDType}}).",
1338                        $data_type_option
1339                    )))
1340                };
1341
1342                unmarshal()
1343            }
1344            _ => Err(crate::error::Error::General(format!(
1345                "Invalid conversion. \
1346                 Cannot convert {:?} into Uuid (valid types: Uuid, Timeuuid, Custom).",
1347                $data_type_option.id
1348            ))),
1349        }
1350    };
1351    ($data_type_option:ident, $data_value:ident, $version:ident, List) => {
1352        match $data_type_option.id {
1353            ColType::List | ColType::Set => match $data_value.as_slice() {
1354                Some(ref bytes) => decode_list(bytes, $version)
1355                    .map(|data| Some(List::new($data_type_option.clone(), data, $version)))
1356                    .map_err(Into::into),
1357                None => Ok(None),
1358            },
1359            _ => Err(crate::error::Error::General(format!(
1360                "Invalid conversion. \
1361                 Cannot convert {:?} into List (valid types: List, Set).",
1362                $data_type_option.id
1363            ))),
1364        }
1365    };
1366    ($data_type_option:ident, $data_value:ident, $version:ident, Vector) => {
1367        match $data_type_option.id {
1368            ColType::Custom => match $data_value.as_slice() {
1369                Some(ref bytes) => {
1370                    let crate::types::vector::VectorInfo { internal_type: _, count  } = crate::types::vector::get_vector_type_info($data_type_option.value.as_ref()?)?;
1371
1372                    decode_float_vector(bytes, $version, count)
1373                        .map(|data| Some(Vector::new($data_type_option.clone(), data, $version)))
1374                        .map_err(Into::into)
1375                },
1376                None => Ok(None),
1377            },
1378            _ => Err(crate::error::Error::(format!(
1379                "Invalid conversion. \
1380                 Cannot convert {:?} into Vector (valid types: Custom).",
1381                $data_type_option.id
1382            ))),
1383        }
1384    };
1385    ($data_type_option:ident, $data_value:ident, $version:ident, Map) => {
1386        match $data_type_option.id {
1387            ColType::Map => match $data_value.as_slice() {
1388                Some(ref bytes) => decode_map(bytes, $version)
1389                    .map(|data| Some(Map::new(data, $data_type_option.clone(), $version)))
1390                    .map_err(Into::into),
1391                None => Ok(None),
1392            },
1393            _ => Err(Error::General(format!(
1394                "Invalid conversion. \
1395                 Cannot convert {:?} into Map (valid types: Map).",
1396                $data_type_option.id
1397            ))),
1398        }
1399    };
1400    ($data_type_option:ident, $data_value:ident, $version:ident, Udt) => {
1401        match *$data_type_option {
1402            ColTypeOption {
1403                id: ColType::Udt,
1404                value: Some(ColTypeOptionValue::UdtType(ref list_type_option)),
1405            } => match $data_value.as_slice() {
1406                Some(ref bytes) => decode_udt(bytes, list_type_option.descriptions.len(), $version)
1407                    .map(|data| Some(Udt::new(data, list_type_option, $version)))
1408                    .map_err(Into::into),
1409                None => Ok(None),
1410            },
1411            _ => Err(Error::General(format!(
1412                "Invalid conversion. \
1413                 Cannot convert {:?} into Udt (valid types: Udt).",
1414                $data_type_option.id
1415            ))),
1416        }
1417    };
1418    ($data_type_option:ident, $data_value:ident, $version:ident, Tuple) => {
1419        match *$data_type_option {
1420            ColTypeOption {
1421                id: ColType::Tuple,
1422                value: Some(ColTypeOptionValue::TupleType(ref list_type_option)),
1423            } => match $data_value.as_slice() {
1424                Some(ref bytes) => decode_tuple(bytes, list_type_option.types.len(), $version)
1425                    .map(|data| Some(Tuple::new(data, list_type_option, $version)))
1426                    .map_err(Into::into),
1427                None => Ok(None),
1428            },
1429            _ => Err(Error::General(format!(
1430                "Invalid conversion. \
1431                 Cannot convert {:?} into Tuple (valid types: Tuple).",
1432                $data_type_option.id
1433            ))),
1434        }
1435    };
1436    ($data_type_option:ident, $data_value:ident, PrimitiveDateTime) => {
1437        match $data_type_option.id {
1438            ColType::Timestamp => match $data_value.as_slice() {
1439                Some(ref bytes) => decode_timestamp(bytes)
1440                    .map(|ts| {
1441                        let unix_epoch = time::macros::date!(1970 - 01 - 01).midnight();
1442                        let tm = unix_epoch
1443                            + time::Duration::new(ts / 1_000, (ts % 1_000 * 1_000_000) as i32);
1444                        Some(tm)
1445                    })
1446                    .map_err(Into::into),
1447                None => Ok(None),
1448            },
1449            _ => Err(Error::General(format!(
1450                "Invalid conversion. \
1451                 Cannot convert {:?} into PrimitiveDateTime (valid types: Timestamp).",
1452                $data_type_option.id
1453            ))),
1454        }
1455    };
1456    ($data_type_option:ident, $data_value:ident, Decimal) => {
1457        match $data_type_option.id {
1458            ColType::Decimal => match $data_value.as_slice() {
1459                Some(ref bytes) => decode_decimal(bytes).map(Some).map_err(Into::into),
1460                None => Ok(None),
1461            },
1462            _ => Err(crate::error::Error::General(format!(
1463                "Invalid conversion. \
1464                 Cannot convert {:?} into Decimal (valid types: Decimal).",
1465                $data_type_option.id
1466            ))),
1467        }
1468    };
1469    ($data_type_option:ident, $data_value:ident, NaiveDateTime) => {
1470        match $data_type_option.id {
1471            ColType::Timestamp => match $data_value.as_slice() {
1472                Some(ref bytes) => decode_timestamp(bytes)
1473                    .map(|ts| {
1474                        DateTime::from_timestamp(ts / 1000, (ts % 1000 * 1_000_000) as u32)
1475                            .map(|dt| dt.naive_utc())
1476                    })
1477                    .map_err(Into::into),
1478                None => Ok(None),
1479            },
1480            _ => Err(Error::General(format!(
1481                "Invalid conversion. \
1482                 Cannot convert {:?} into NaiveDateTime (valid types: Timestamp).",
1483                $data_type_option.id
1484            ))),
1485        }
1486    };
1487    ($data_type_option:ident, $data_value:ident, DateTime<Utc>) => {
1488        match $data_type_option.id {
1489            ColType::Timestamp => match $data_value.as_slice() {
1490                Some(ref bytes) => decode_timestamp(bytes)
1491                    .map(|ts| {
1492                        DateTime::from_timestamp(
1493                            ts / 1000,
1494                            (ts % 1000 * 1_000_000) as u32,
1495                        )
1496                    })
1497                    .map_err(Into::into),
1498                None => Ok(None),
1499            },
1500            _ => Err(Error::General(format!(
1501                "Invalid conversion. \
1502                 Cannot convert {:?} into DateTime (valid types: Timestamp).",
1503                $data_type_option.id
1504            ))),
1505        }
1506    };
1507    ($data_type_option:ident, $data_value:ident, BigInt) => {
1508        match $data_type_option.id {
1509            ColType::Varint => {
1510                as_res_opt!($data_value, decode_varint)
1511            }
1512            ColType::Custom => {
1513                let unmarshal = || {
1514                    if let Some(ColTypeOptionValue::CString(value)) = &$data_type_option.value {
1515                        if value.as_str() == "org.apache.cassandra.db.marshal.IntegerType" {
1516                            return as_res_opt!($data_value, decode_varint);
1517                        }
1518                    }
1519
1520                    Err(crate::error::Error::General(format!(
1521                        "Invalid conversion. \
1522                         Cannot convert marshalled type {:?} into BigInt (valid types: org.apache.cassandra.db.marshal.IntegerType).",
1523                        $data_type_option
1524                    )))
1525                };
1526
1527                unmarshal()
1528            }
1529            _ => Err(crate::error::Error::General(format!(
1530                "Invalid conversion. \
1531                 Cannot convert {:?} into BigInt (valid types: Varint, Custom)",
1532                $data_type_option.id
1533            ))),
1534        }
1535    };
1536    ($data_type_option:ident, $data_value:ident, Duration) => {
1537        match $data_type_option.id {
1538            ColType::Duration => {
1539                as_res_opt!($data_value, decode_duration)
1540            }
1541            ColType::Custom => {
1542                let unmarshal = || {
1543                    if let Some(ColTypeOptionValue::CString(value)) = &$data_type_option.value {
1544                        if value.as_str() == "org.apache.cassandra.db.marshal.DurationType" {
1545                            return as_res_opt!($data_value, decode_duration);
1546                        }
1547                    }
1548
1549                    Err(crate::error::Error::General(format!(
1550                        "Invalid conversion. \
1551                         Cannot convert marshalled type {:?} into Duration (valid types: org.apache.cassandra.db.marshal.DurationType).",
1552                        $data_type_option
1553                    )))
1554                };
1555
1556                unmarshal()
1557            }
1558            _ => Err(crate::error::Error::General(format!(
1559                "Invalid conversion. \
1560                 Cannot convert {:?} into Duration (valid types: Duration, Custom)",
1561                $data_type_option.id
1562            ))),
1563        }
1564    };
1565}