Repository: AlexPikalov/cdrs (language: rust)

Issue:
Simplify process of Cassandra list to Vec convertation
At the moment a process of conversion from Cassandra `list` to Rust `Vec<T>` look a bit complicated comparing to conversion of primitive type. A developer has to perform it in two steps: 1.) convert bytes into CDRS `List` and then convert `List` into Rust `Vec<T>`. The same situation for Cassandra set and map.

The goal is to eliminate this intermediate step and to enable a direct conversion from list to `Vec<T>`


Discussion / hints:

Fix patch:
diff --git a/.travis.yml b/.travis.yml
index 49e98b8..9e149f1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,15 +8,15 @@ matrix:
   allow_failures:
     - rust: nightly
 
-
-before_install:
-  - sudo update-java-alternatives -s java-8-oracle
-  - export JAVA_HOME=/usr/lib/jvm/java-8-oracle
-  - java -version
-  - sudo rm -rf /var/lib/cassandra/*
-  - if [ ! -d "apache-cassandra-3.9" ]; then wget http://www.us.apache.org/dist/cassandra/3.9/apache-cassandra-3.9-bin.tar.gz && tar -xvzf apache-cassandra-3.9-bin.tar.gz; fi
-  - sudo sh ./apache-cassandra-3.9/bin/cassandra -R
-  - sleep 20
+# Enable when https://blog.travis-ci.com/2017-04-17-precise-EOL is fixed
+#before_install:
+#  - sudo update-java-alternatives -s java-8-oracle
+#  - export JAVA_HOME=/usr/lib/jvm/java-8-oracle
+#  - java -version
+#  - sudo rm -rf /var/lib/cassandra/*
+#  - if [ ! -d "apache-cassandra-3.9" ]; then wget http://www.us.apache.org/dist/cassandra/3.9/apache-cassandra-3.9-bin.tar.gz && tar -xvzf apache-cassandra-3.9-bin.tar.gz; fi
+#  - sudo sh ./apache-cassandra-3.9/bin/cassandra -R
+#  - sleep 20
 
 
 install:
@@ -42,20 +42,20 @@ addons:
       - oracle-java8-installer
 
 
-
-after_success:
-   wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz &&
-   tar xzf master.tar.gz &&
-   cd kcov-master &&
-   mkdir build &&
-   cd build &&
-   cmake .. &&
-   make &&
-   sudo make install &&
-   cd ../.. &&
-   rm -rf kcov-master &&
-   for file in target/debug/cdrs-*; do mkdir -p "target/cov/$(basename $file)"; kcov --exclude-pattern=/.cargo,/usr/lib --verify "target/cov/$(basename $file)" "$file"; done &&
-   bash <(curl -s https://codecov.io/bash) &&
-   rm -rf target/cov &&
-   for file in target/debug/cdrs-*; do mkdir -p "target/coverall/$(basename $file)"; kcov --coveralls-id=$TRAVIS_JOB_ID --exclude-pattern=/.cargo,/usr/lib --verify "target/coverall/$(basename $file)" "$file"; done &&
-   echo "Uploaded code coverage"
+# Enable when https://blog.travis-ci.com/2017-04-17-precise-EOL is fixed
+#after_success:
+#   wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz &&#
+#   tar xzf master.tar.gz &&
+#   cd kcov-master &&
+#   mkdir build &&
+#   cd build &&
+#   cmake .. &&
+#   make &&
+#   sudo make install &&
+#   cd ../.. &&
+#   rm -rf kcov-master &&
+#   for file in target/debug/cdrs-*; do mkdir -p "target/cov/$(basename $file)"; kcov --exclude-pattern=/.cargo,/usr/lib --verify "target/cov/$(basename $file)" "$file"; done &&
+#   bash <(curl -s https://codecov.io/bash) &&
+#   rm -rf target/cov &&
+#   for file in target/debug/cdrs-*; do mkdir -p "target/coverall/$(basename $file)"; kcov --coveralls-id=$TRAVIS_JOB_ID --exclude-pattern=/.cargo,/usr/lib --verify "target/coverall/$(basename $file)" "$file"; done &&
+#   echo "Uploaded code coverage"
diff --git a/examples/all.rs b/examples/all.rs
index 3642011..d5dd267 100644
--- a/examples/all.rs
+++ b/examples/all.rs
@@ -12,7 +12,7 @@ use cdrs::query::{QueryBuilder, QueryParamsBuilder};
 use cdrs::authenticators::NoneAuthenticator;
 use cdrs::compression::Compression;
 use cdrs::transport::TransportTcp;
-use cdrs::types::{IntoRustByName, CBytesShort, AsRust};
+use cdrs::types::{IntoRustByName, CBytesShort, AsRust, ByName};
 use cdrs::types::value::{Value, Bytes};
 use cdrs::types::list::List;
 use cdrs::types::map::Map;
@@ -419,22 +419,23 @@ fn select_table_list(session: &mut Session<NoneAuthenticator, TransportTcp>) ->
         .unwrap();
 
     for row in all {
-        let cl = CassandraLists {
-            string_list: row.get_by_name("my_string_list")
+        let _ = Lists {
+            string_list: row.by_name::<List>("my_string_list") // intermediate type is required
                 .expect("string_list")
-                .unwrap(),
-            number_list: row.get_by_name("my_number_list")
+                .unwrap()
+                .as_rust::<Vec<String>>() // final type is not required, it could be find
+                // authomatically
+                .expect("string_list"),
+            number_list: row.by_name::<List>("my_number_list")
                 .expect("number_list")
-                .unwrap(),
-            complex_list: row.get_by_name("my_complex_list")
+                .unwrap()
+                .as_rust()
+                .expect("number_list"),
+            complex_list: row.by_name::<List>("my_complex_list")
                 .expect("complex_list")
-                .unwrap(),
-        };
-        let complex_list_c: Vec<List> = cl.complex_list.as_rust().expect("my_complex_list");
-        let _ = Lists {
-            string_list: cl.string_list.as_rust().expect("string_list"),
-            number_list: cl.number_list.as_rust().expect("number_list"),
-            complex_list: complex_list_c
+                .unwrap()
+                .as_rust::<Vec<List>>()
+                .expect("my_complex_list")
                 .iter()
                 .map(|it| it.as_rust().expect("number_list_c"))
                 .collect(),
@@ -491,35 +492,37 @@ fn select_table_map(session: &mut Session<NoneAuthenticator, TransportTcp>) -> b
         .unwrap();
 
     for row in all {
-        let cm = CassandraMaps {
-            string_map: row.get_by_name("my_string_map")
+        let _ = Maps {
+            string_map: row.by_name::<Map>("my_string_map")
                 .expect("string_map")
-                .unwrap(),
-            number_map: row.get_by_name("my_number_map")
+                .unwrap()
+                .as_rust()
+                .expect("string_map"),
+            number_map: row.by_name::<Map>("my_number_map")
                 .expect("number_map")
-                .unwrap(),
-            complex_map: row.get_by_name("my_complex_map")
+                .unwrap()
+                .as_rust()
+                .expect("number_map"),
+            complex_map: row.by_name::<Map>("my_complex_map")
                 .expect("complex_map")
-                .unwrap(),
-            int_key_map: row.get_by_name("my_int_key_map")
-                .expect("int_key_map")
-                .unwrap(),
-            uuid_key_map: row.get_by_name("my_uuid_key_map")
-                .expect("uuid_key_map")
-                .unwrap(),
-        };
-        let complex_map_c: HashMap<String, Map> = cm.complex_map.as_rust().expect("my_complex_map");
-        let _ = Maps {
-            string_map: cm.string_map.as_rust().expect("string_map"),
-            number_map: cm.number_map.as_rust().expect("number_map"),
-            complex_map: complex_map_c
+                .unwrap()
+                .as_rust::<HashMap<String, Map>>()
+                .expect("my_complex_map")
                 .iter()
                 .fold(HashMap::new(), |mut hm, (k, v)| {
                     hm.insert(k.clone(), v.as_rust().expect("complex_map_c"));
                     hm
                 }),
-            int_key_map: cm.int_key_map.as_rust().expect("int_key_map"),
-            uuid_key_map: cm.uuid_key_map.as_rust().expect("uuid_key_map"),
+            int_key_map: row.by_name::<Map>("my_int_key_map")
+                .expect("int_key_map")
+                .unwrap()
+                .as_rust()
+                .expect("int_key_map"),
+            uuid_key_map: row.by_name::<Map>("my_uuid_key_map")
+                .expect("uuid_key_map")
+                .unwrap()
+                .as_rust()
+                .expect("uuid_key_map"),
         };
     }
 
@@ -566,8 +569,14 @@ fn select_table_udt(session: &mut Session<NoneAuthenticator, TransportTcp>) -> b
         .unwrap();
 
     for row in all {
-        let udt_c: UDT = row.get_by_name("my_udt").expect("my_udt").unwrap();
-        let _ = Udt { number: udt_c.get_by_name("number").expect("number").unwrap() };
+        let _ = Udt {
+            number: row.by_name::<UDT>("my_udt")
+                .expect("my_udt")
+                .unwrap()
+                .by_name("number")
+                .expect("number")
+                .unwrap(),
+        };
     }
 
     true
@@ -796,13 +805,6 @@ struct Lists {
     pub complex_list: Vec<Vec<i16>>,
 }
 
-#[derive(Debug)]
-struct CassandraLists {
-    pub string_list: List,
-    pub number_list: List,
-    pub complex_list: List,
-}
-
 #[derive(Debug)]
 struct Maps {
     pub string_map: HashMap<String, String>,
@@ -812,14 +814,6 @@ struct Maps {
     pub uuid_key_map: HashMap<Uuid, String>,
 }
 
-struct CassandraMaps {
-    pub string_map: Map,
-    pub number_map: Map,
-    pub complex_map: Map,
-    pub int_key_map: Map,
-    pub uuid_key_map: Map,
-}
-
 #[derive(Debug)]
 struct Udt {
     pub number: i32,
diff --git a/src/macros.rs b/src/macros.rs
index 73b5708..65b58e2 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -25,14 +25,15 @@ macro_rules! builder_opt_field {
 
 macro_rules! list_as_rust {
     ($($into_type:tt)*) => (
-        impl AsRust<Vec<$($into_type)*>> for List {
-            fn as_rust(&self) -> Result<Vec<$($into_type)*>> {
+        impl AsRustType<Vec<$($into_type)*>> for List {
+            fn as_rust_type(&self) -> Result<Vec<$($into_type)*>> {
                 match self.metadata.value {
                     Some(ColTypeOptionValue::CList(ref type_option)) |
                     Some(ColTypeOptionValue::CSet(ref type_option)) => {
                         let type_option_ref = type_option.as_ref();
                         let convert = self
-                            .map(|bytes| as_rust!(type_option_ref, bytes, $($into_type)*).unwrap());
+                            .map(|bytes| as_rust_type!(type_option_ref, bytes, $($into_type)*)
+                                .unwrap());
 
                         Ok(convert)
                     },
@@ -49,9 +50,9 @@ macro_rules! list_as_rust {
 
 macro_rules! map_as_rust {
     ($(K $key_type:tt)*, $(V $val_type:tt)*) => (
-        impl AsRust<HashMap<$($key_type)*, $($val_type)*>> for Map {
+        impl AsRustType<HashMap<$($key_type)*, $($val_type)*>> for Map {
             /// Converts `Map` into `HashMap` for blob values.
-            fn as_rust(&self) -> Result<HashMap<$($key_type)*, $($val_type)*>> {
+            fn as_rust_type(&self) -> Result<HashMap<$($key_type)*, $($val_type)*>> {
                 match self.metadata.value {
                     Some(ColTypeOptionValue::CMap((ref key_type_option, ref val_type_option))) => {
                         let mut map = HashMap::with_capacity(self.data.len());
@@ -59,8 +60,8 @@ macro_rules! map_as_rust {
                         for &(ref key, ref val) in self.data.iter() {
                             let key_type_option = key_type_option.as_ref();
                             let val_type_option = val_type_option.as_ref();
-                            let key = as_rust!(key_type_option, key, $($key_type)*)?;
-                            let val = as_rust!(val_type_option, val, $($val_type)*)?;
+                            let key = as_rust_type!(key_type_option, key, $($key_type)*)?;
+                            let val = as_rust_type!(val_type_option, val, $($val_type)*)?;
                             map.insert(key, val);
                         }
 
@@ -87,7 +88,7 @@ macro_rules! into_rust_by_name {
                         }
 
                         let ref col_type = col_spec.col_type;
-                        as_rust!(col_type, cbytes, $($into_type)*)
+                        as_rust_type!(col_type, cbytes, $($into_type)*)
                     })
             }
         }
@@ -103,7 +104,7 @@ macro_rules! into_rust_by_name {
                         return Err(column_is_empty_err());
                     }
 
-                    let converted = as_rust!(col_type, bytes, $($into_type)*);
+                    let converted = as_rust_type!(col_type, bytes, $($into_type)*);
                     converted.map_err(|err| err.into())
                 })
             }
@@ -117,7 +118,7 @@ macro_rules! into_rust_by_name {
 /// Decodes any Cassandra data type into the corresponding Rust type,
 /// given the column type as `ColTypeOption` and the value as `CBytes`
 /// plus the matching Rust type.
-macro_rules! as_rust {
+macro_rules! as_rust_type {
     ($data_type_option:ident, $data_value:ident, Vec<u8>) => (
         match $data_type_option.id {
             ColType::Blob => {
diff --git a/src/types/data_serialization_types.rs b/src/types/data_serialization_types.rs
index 7befdda..47642b0 100644
--- a/src/types/data_serialization_types.rs
+++ b/src/types/data_serialization_types.rs
@@ -339,9 +339,9 @@ mod tests {
     fn as_rust_blob_test() {
         let d_type = DataType { id: ColType::Blob };
         let data = CBytes::new(vec![1, 2, 3]);
-        assert_eq!(as_rust!(d_type, data, Vec<u8>).unwrap(), vec![1, 2, 3]);
+        assert_eq!(as_rust_type!(d_type, data, Vec<u8>).unwrap(), vec![1, 2, 3]);
         let wrong_type = DataType { id: ColType::Map };
-        assert!(as_rust!(wrong_type, data, Vec<u8>).is_err());
+        assert!(as_rust_type!(wrong_type, data, Vec<u8>).is_err());
     }
 
     #[test]
@@ -350,11 +350,11 @@ mod tests {
         let type_ascii = DataType { id: ColType::Ascii };
         let type_varchar = DataType { id: ColType::Varchar };
         let data = CBytes::new(b"abc".to_vec());
-        assert_eq!(as_rust!(type_custom, data, String).unwrap(), "abc");
-        assert_eq!(as_rust!(type_ascii, data, String).unwrap(), "abc");
-        assert_eq!(as_rust!(type_varchar, data, String).unwrap(), "abc");
+        assert_eq!(as_rust_type!(type_custom, data, String).unwrap(), "abc");
+        assert_eq!(as_rust_type!(type_ascii, data, String).unwrap(), "abc");
+        assert_eq!(as_rust_type!(type_varchar, data, String).unwrap(), "abc");
         let wrong_type = DataType { id: ColType::Map };
-        assert!(as_rust!(wrong_type, data, String).is_err());
+        assert!(as_rust_type!(wrong_type, data, String).is_err());
     }
 
     #[test]
@@ -362,10 +362,10 @@ mod tests {
         let type_boolean = DataType { id: ColType::Boolean };
         let data_true = CBytes::new(vec![1]);
         let data_false = CBytes::new(vec![0]);
-        assert_eq!(as_rust!(type_boolean, data_true, bool).unwrap(), true);
-        assert_eq!(as_rust!(type_boolean, data_false, bool).unwrap(), false);
+        assert_eq!(as_rust_type!(type_boolean, data_true, bool).unwrap(), true);
+        assert_eq!(as_rust_type!(type_boolean, data_false, bool).unwrap(), false);
         let wrong_type = DataType { id: ColType::Map };
-        assert!(as_rust!(wrong_type, data_false, bool).is_err());
+        assert!(as_rust_type!(wrong_type, data_false, bool).is_err());
     }
 
     #[test]
@@ -375,12 +375,12 @@ mod tests {
         let type_time = DataType { id: ColType::Time };
         let type_varint = DataType { id: ColType::Varint };
         let data = CBytes::new(vec![0, 0, 0, 0, 0, 0, 0, 100]);
-        assert_eq!(as_rust!(type_bigint, data, i64).unwrap(), 100);
-        assert_eq!(as_rust!(type_timestamp, data, i64).unwrap(), 100);
-        assert_eq!(as_rust!(type_time, data, i64).unwrap(), 100);
-        assert_eq!(as_rust!(type_varint, data, i64).unwrap(), 100);
+        assert_eq!(as_rust_type!(type_bigint, data, i64).unwrap(), 100);
+        assert_eq!(as_rust_type!(type_timestamp, data, i64).unwrap(), 100);
+        assert_eq!(as_rust_type!(type_time, data, i64).unwrap(), 100);
+        assert_eq!(as_rust_type!(type_varint, data, i64).unwrap(), 100);
         let wrong_type = DataType { id: ColType::Map };
-        assert!(as_rust!(wrong_type, data, i64).is_err());
+        assert!(as_rust_type!(wrong_type, data, i64).is_err());
     }
 
     #[test]
@@ -388,37 +388,37 @@ mod tests {
         let type_int = DataType { id: ColType::Int };
         let type_date = DataType { id: ColType::Date };
         let data = CBytes::new(vec![ 0, 0, 0, 100]);
-        assert_eq!(as_rust!(type_int, data, i32).unwrap(), 100);
-        assert_eq!(as_rust!(type_date, data, i32).unwrap(), 100);
+        assert_eq!(as_rust_type!(type_int, data, i32).unwrap(), 100);
+        assert_eq!(as_rust_type!(type_date, data, i32).unwrap(), 100);
         let wrong_type = DataType { id: ColType::Map };
-        assert!(as_rust!(wrong_type, data, i32).is_err());
+        assert!(as_rust_type!(wrong_type, data, i32).is_err());
     }
 
     #[test]
     fn as_rust_i16_test() {
         let type_smallint = DataType { id: ColType::Smallint };
         let data = CBytes::new(vec![0, 100]);
-        assert_eq!(as_rust!(type_smallint, data, i16).unwrap(), 100);
+        assert_eq!(as_rust_type!(type_smallint, data, i16).unwrap(), 100);
         let wrong_type = DataType { id: ColType::Map };
-        assert!(as_rust!(wrong_type, data, i16).is_err());
+        assert!(as_rust_type!(wrong_type, data, i16).is_err());
     }
 
     #[test]
     fn as_rust_i8_test() {
         let type_tinyint = DataType { id: ColType::Tinyint };
         let data = CBytes::new(vec![100]);
-        assert_eq!(as_rust!(type_tinyint, data, i8).unwrap(), 100);
+        assert_eq!(as_rust_type!(type_tinyint, data, i8).unwrap(), 100);
         let wrong_type = DataType { id: ColType::Map };
-        assert!(as_rust!(wrong_type, data, i8).is_err());
+        assert!(as_rust_type!(wrong_type, data, i8).is_err());
     }
 
     #[test]
     fn as_rust_f64_test() {
         let type_double = DataType { id: ColType::Double };
         let data = CBytes::new(to_float_big(0.1 as f64));
-        assert_eq!(as_rust!(type_double, data, f64).unwrap(), 0.1);
+        assert_eq!(as_rust_type!(type_double, data, f64).unwrap(), 0.1);
         let wrong_type = DataType { id: ColType::Map };
-        assert!(as_rust!(wrong_type, data, f64).is_err());
+        assert!(as_rust_type!(wrong_type, data, f64).is_err());
     }
 
     #[test]
@@ -426,10 +426,10 @@ mod tests {
         // let type_decimal = DataType { id: ColType::Decimal };
         let type_float = DataType { id: ColType::Float };
         let data = CBytes::new(to_float(0.1 as f32));
-        // assert_eq!(as_rust!(type_decimal, data, f32).unwrap(), 100.0);
-        assert_eq!(as_rust!(type_float, data, f32).unwrap(), 0.1);
+        // assert_eq!(as_rust_type!(type_decimal, data, f32).unwrap(), 100.0);
+        assert_eq!(as_rust_type!(type_float, data, f32).unwrap(), 0.1);
         let wrong_type = DataType { id: ColType::Map };
-        assert!(as_rust!(wrong_type, data, f32).is_err());
+        assert!(as_rust_type!(wrong_type, data, f32).is_err());
     }
 
     #[test]
@@ -437,12 +437,12 @@ mod tests {
         let type_inet = DataType { id: ColType::Inet };
         let data = CBytes::new(vec![0, 0, 0, 0]);
 
-        match as_rust!(type_inet, data, IpAddr) {
+        match as_rust_type!(type_inet, data, IpAddr) {
             Ok(IpAddr::V4(ref ip)) => assert_eq!(ip.octets(), [0, 0, 0, 0]),
             _ => panic!("wrong ip v4 address"),
         }
         let wrong_type = DataType { id: ColType::Map };
-        assert!(as_rust!(wrong_type, data, f32).is_err());
+        assert!(as_rust_type!(wrong_type, data, f32).is_err());
     }
 
     struct DataType {
diff --git a/src/types/list.rs b/src/types/list.rs
index cedd480..2c18191 100644
--- a/src/types/list.rs
+++ b/src/types/list.rs
@@ -1,7 +1,7 @@
 use std::net::IpAddr;
 use uuid::Uuid;
 use frame::frame_result::{ColType, ColTypeOptionValue, ColTypeOption};
-use types::{CBytes, AsRust};
+use types::{CBytes, AsRustType, AsRust};
 use types::data_serialization_types::*;
 use types::map::Map;
 use types::udt::UDT;
@@ -31,9 +31,11 @@ impl List {
     }
 }
 
-impl AsRust<Vec<Vec<u8>>> for List {
+impl AsRust for List {}
+
+impl AsRustType<Vec<Vec<u8>>> for List {
     /// Converts cassandra list of blobs into Rust `Vec<Vec<u8>>`
-    fn as_rust(&self) -> Result<Vec<Vec<u8>>> {
+    fn as_rust_type(&self) -> Result<Vec<Vec<u8>>> {
         match self.metadata.value {
             Some(ColTypeOptionValue::CList(ref type_option)) => {
                 match type_option.id {
diff --git a/src/types/map.rs b/src/types/map.rs
index 647b13d..706eb34 100644
--- a/src/types/map.rs
+++ b/src/types/map.rs
@@ -2,7 +2,7 @@ use std::collections::HashMap;
 use std::net::IpAddr;
 use uuid::Uuid;
 
-use types::{AsRust, CBytes};
+use types::{AsRustType, CBytes, AsRust};
 use frame::frame_result::{ColTypeOption, ColTypeOptionValue, ColType};
 use types::data_serialization_types::*;
 use types::list::List;
@@ -25,6 +25,7 @@ impl Map {
     }
 }
 
+impl AsRust for Map {}
 
 // Generate `AsRust` implementations for all kinds of map types.
 // The macro `map_as_rust!` takes the types as lists of token trees,
diff --git a/src/types/mod.rs b/src/types/mod.rs
index 9e61062..e51dd40 100644
--- a/src/types/mod.rs
+++ b/src/types/mod.rs
@@ -23,8 +23,16 @@ pub mod value;
 
 /// Should be used to represent a single column as a Rust value.
 // TODO: change Option to Result, create a new type of error for that.
-pub trait AsRust<T> {
-    fn as_rust(&self) -> CDRSResult<T>;
+pub trait AsRustType<T> {
+    fn as_rust_type(&self) -> CDRSResult<T>;
+}
+
+pub trait AsRust {
+    fn as_rust<R>(&self) -> CDRSResult<R>
+        where Self: AsRustType<R>
+    {
+        self.as_rust_type()
+    }
 }
 
 /// Should be used to return a single column as Rust value by its name.
@@ -32,6 +40,14 @@ pub trait IntoRustByName<R> {
     fn get_by_name(&self, name: &str) -> Option<CDRSResult<R>>;
 }
 
+pub trait ByName {
+    fn by_name<R>(&self, name: &str) -> Option<CDRSResult<R>>
+        where Self: IntoRustByName<R>
+    {
+        self.get_by_name(name)
+    }
+}
+
 /// Tries to converts u64 numerical value into array of n bytes.
 pub fn try_to_n_bytes(int: u64, n: usize) -> io::Result<Vec<u8>> {
     let mut bytes = vec![];
diff --git a/src/types/rows.rs b/src/types/rows.rs
index 564fb9b..b02b31c 100644
--- a/src/types/rows.rs
+++ b/src/types/rows.rs
@@ -4,7 +4,7 @@ use time::Timespec;
 
 use frame::frame_result::{RowsMetadata, ColType, ColSpec, BodyResResultRows, ColTypeOption,
                           ColTypeOptionValue};
-use types::{CBytes, IntoRustByName};
+use types::{CBytes, IntoRustByName, ByName};
 use types::data_serialization_types::*;
 use types::list::List;
 use types::map::Map;
@@ -48,11 +48,13 @@ impl IntoRustByName<Vec<u8>> for Row {
         self.get_col_spec_by_name(name)
             .map(|(col_spec, cbytes)| {
                      let ref col_type = col_spec.col_type;
-                     as_rust!(col_type, cbytes, Vec<u8>)
+                     as_rust_type!(col_type, cbytes, Vec<u8>)
                  })
     }
 }
 
+impl ByName for Row {}
+
 into_rust_by_name!(Row, String);
 into_rust_by_name!(Row, bool);
 into_rust_by_name!(Row, i64);
diff --git a/src/types/udt.rs b/src/types/udt.rs
index 487bcad..7a928d7 100644
--- a/src/types/udt.rs
+++ b/src/types/udt.rs
@@ -3,7 +3,7 @@ use std::collections::HashMap;
 use uuid::Uuid;
 
 use frame::frame_result::{ColTypeOption, CUdt, ColType, ColTypeOptionValue};
-use types::{CBytes, IntoRustByName};
+use types::{CBytes, IntoRustByName, ByName};
 use types::data_serialization_types::*;
 use types::list::List;
 use types::map::Map;
@@ -36,17 +36,21 @@ impl UDT {
 
 impl IntoRustByName<Vec<u8>> for UDT {
     fn get_by_name(&self, name: &str) -> Option<Result<Vec<u8>>> {
-        self.data.get(name).map(|v| {
-            let &(ref col_type, ref bytes) = v;
-
-            match col_type.id {
-                ColType::Blob => decode_blob(bytes.as_plain()).map_err(|err| err.into()),
-                _ => Err(Error::General(format!("Cannot parse  {:?} into UDT ", col_type.id))),
-            }
-        })
+        self.data
+            .get(name)
+            .map(|v| {
+                let &(ref col_type, ref bytes) = v;
+
+                match col_type.id {
+                    ColType::Blob => decode_blob(bytes.as_plain()).map_err(|err| err.into()),
+                    _ => Err(Error::General(format!("Cannot parse  {:?} into UDT ", col_type.id))),
+                }
+            })
     }
 }
 
+impl ByName for UDT {}
+
 into_rust_by_name!(UDT, String);
 into_rust_by_name!(UDT, bool);
 into_rust_by_name!(UDT, i64);


Test patch:
diff --git a/tests/create_insert_table.rs b/tests/create_insert_table.rs
index eab1f48..48ca0f1 100644
--- a/tests/create_insert_table.rs
+++ b/tests/create_insert_table.rs
@@ -35,8 +35,8 @@ struct User {
     pub some_map: Option<Map>,
 }
 
-#[cfg(not(windows))]
-#[test]
+// #[cfg(not(windows))]
+// #[test]
 fn write_and_read_from_cassandra() {
     run_test(|| read_write())
 }
diff --git a/tests/crud_operations.rs b/tests/crud_operations.rs
index 452e952..334ec34 100644
--- a/tests/crud_operations.rs
+++ b/tests/crud_operations.rs
@@ -1,4 +1,4 @@
-// TODO: add update and delete operations
+
 extern crate cdrs;
 extern crate uuid;
 extern crate time;
@@ -12,7 +12,7 @@ use cdrs::query::{QueryBuilder, QueryParamsBuilder};
 use cdrs::authenticators::NoneAuthenticator;
 use cdrs::compression::Compression;
 use cdrs::transport::TransportTcp;
-use cdrs::types::{IntoRustByName, CBytesShort, AsRust};
+use cdrs::types::{IntoRustByName, CBytesShort, AsRust, ByName};
 use cdrs::types::value::{Value, Bytes};
 use cdrs::types::list::List;
 use cdrs::types::map::Map;
@@ -46,7 +46,7 @@ const INSERT_MAP: &'static str = "INSERT INTO my_ks.maps (my_string_map, my_numb
                                   ?, ?, ?);";
 const SELECT_MAP: &'static str = "SELECT * FROM my_ks.maps;";
 const CREATE_TABLE_UDT: &'static str = "CREATE TABLE IF NOT EXISTS my_ks.udts (my_key int \
-                                        PRIMARY KEY, my_udt frozen<my_type>);";
+                                        PRIMARY KEY, my_udt my_type);";
 const INSERT_UDT: &'static str = "INSERT INTO my_ks.udts (my_key, my_udt) VALUES (?, ?);";
 const SELECT_UDT: &'static str = "SELECT * FROM my_ks.udts;";
 const INSERT_INT: &'static str = "INSERT INTO my_ks.test_num (my_bigint, my_int, my_smallint, \
@@ -86,8 +86,9 @@ const SELECT_TIMESTAMP: &'static str = "SELECT * FROM my_ks.timestamp;";
 // 5. select values from x and map to Rust
 // ...
 
-#[cfg(not(windows))]
-#[test]
+// Enable when https://blog.travis-ci.com/2017-04-17-precise-EOL is fixed
+// #[cfg(not(windows))]
+// #[test]
 fn main_crud_operations() {
     let authenticator = NoneAuthenticator;
     let tcp_transport = TransportTcp::new(_ADDR).unwrap();
@@ -428,22 +429,23 @@ fn select_table_list(session: &mut Session<NoneAuthenticator, TransportTcp>) ->
         .unwrap();
 
     for row in all {
-        let cl = CassandraLists {
-            string_list: row.get_by_name("my_string_list")
+        let _ = Lists {
+            string_list: row.by_name::<List>("my_string_list") // intermediate type is required
                 .expect("string_list")
-                .unwrap(),
-            number_list: row.get_by_name("my_number_list")
+                .unwrap()
+                .as_rust::<Vec<String>>() // final type is not required, it could be find
+                // authomatically
+                .expect("string_list"),
+            number_list: row.by_name::<List>("my_number_list")
                 .expect("number_list")
-                .unwrap(),
-            complex_list: row.get_by_name("my_complex_list")
+                .unwrap()
+                .as_rust()
+                .expect("number_list"),
+            complex_list: row.by_name::<List>("my_complex_list")
                 .expect("complex_list")
-                .unwrap(),
-        };
-        let complex_list_c: Vec<List> = cl.complex_list.as_rust().expect("my_complex_list");
-        let _ = Lists {
-            string_list: cl.string_list.as_rust().expect("string_list"),
-            number_list: cl.number_list.as_rust().expect("number_list"),
-            complex_list: complex_list_c
+                .unwrap()
+                .as_rust::<Vec<List>>()
+                .expect("my_complex_list")
                 .iter()
                 .map(|it| it.as_rust().expect("number_list_c"))
                 .collect(),
@@ -500,35 +502,37 @@ fn select_table_map(session: &mut Session<NoneAuthenticator, TransportTcp>) -> b
         .unwrap();
 
     for row in all {
-        let cm = CassandraMaps {
-            string_map: row.get_by_name("my_string_map")
+        let _ = Maps {
+            string_map: row.by_name::<Map>("my_string_map")
                 .expect("string_map")
-                .unwrap(),
-            number_map: row.get_by_name("my_number_map")
+                .unwrap()
+                .as_rust()
+                .expect("string_map"),
+            number_map: row.by_name::<Map>("my_number_map")
                 .expect("number_map")
-                .unwrap(),
-            complex_map: row.get_by_name("my_complex_map")
+                .unwrap()
+                .as_rust()
+                .expect("number_map"),
+            complex_map: row.by_name::<Map>("my_complex_map")
                 .expect("complex_map")
-                .unwrap(),
-            int_key_map: row.get_by_name("my_int_key_map")
-                .expect("int_key_map")
-                .unwrap(),
-            uuid_key_map: row.get_by_name("my_uuid_key_map")
-                .expect("uuid_key_map")
-                .unwrap(),
-        };
-        let complex_map_c: HashMap<String, Map> = cm.complex_map.as_rust().expect("my_complex_map");
-        let _ = Maps {
-            string_map: cm.string_map.as_rust().expect("string_map"),
-            number_map: cm.number_map.as_rust().expect("number_map"),
-            complex_map: complex_map_c
+                .unwrap()
+                .as_rust::<HashMap<String, Map>>()
+                .expect("my_complex_map")
                 .iter()
                 .fold(HashMap::new(), |mut hm, (k, v)| {
                     hm.insert(k.clone(), v.as_rust().expect("complex_map_c"));
                     hm
                 }),
-            int_key_map: cm.int_key_map.as_rust().expect("int_key_map"),
-            uuid_key_map: cm.uuid_key_map.as_rust().expect("uuid_key_map"),
+            int_key_map: row.by_name::<Map>("my_int_key_map")
+                .expect("int_key_map")
+                .unwrap()
+                .as_rust()
+                .expect("int_key_map"),
+            uuid_key_map: row.by_name::<Map>("my_uuid_key_map")
+                .expect("uuid_key_map")
+                .unwrap()
+                .as_rust()
+                .expect("uuid_key_map"),
         };
     }
 
@@ -575,8 +579,14 @@ fn select_table_udt(session: &mut Session<NoneAuthenticator, TransportTcp>) -> b
         .unwrap();
 
     for row in all {
-        let udt_c: UDT = row.get_by_name("my_udt").expect("my_udt").unwrap();
-        let _ = Udt { number: udt_c.get_by_name("number").expect("number").unwrap() };
+        let _ = Udt {
+            number: row.by_name::<UDT>("my_udt")
+                .expect("my_udt")
+                .unwrap()
+                .by_name("number")
+                .expect("number")
+                .unwrap(),
+        };
     }
 
     true
@@ -813,13 +823,6 @@ struct Lists {
     pub complex_list: Vec<Vec<i16>>,
 }
 
-#[derive(Debug)]
-struct CassandraLists {
-    pub string_list: List,
-    pub number_list: List,
-    pub complex_list: List,
-}
-
 #[derive(Debug)]
 struct Maps {
     pub string_map: HashMap<String, String>,
@@ -829,14 +832,6 @@ struct Maps {
     pub uuid_key_map: HashMap<Uuid, String>,
 }
 
-struct CassandraMaps {
-    pub string_map: Map,
-    pub number_map: Map,
-    pub complex_map: Map,
-    pub int_key_map: Map,
-    pub uuid_key_map: Map,
-}
-
 #[derive(Debug)]
 struct Udt {
     pub number: i32,
diff --git a/tests/simple_connect.rs b/tests/simple_connect.rs
index da8ddcd..44b5327 100644
--- a/tests/simple_connect.rs
+++ b/tests/simple_connect.rs
@@ -12,8 +12,8 @@ const _ADDR: &'static str = "127.0.0.1:9042";
 
 
 
-#[cfg(not(windows))]
-#[test]
+// #[cfg(not(windows))]
+// #[test]
 fn connect_to_cassandra() {
     const _ADDR: &'static str = "127.0.0.1:9042";
     let authenticator = NoneAuthenticator;