extern crate csv; extern crate serde; #[macro_use] extern crate serde_derive; extern crate serde_qs as qs; use serde::de::DeserializeOwned; use std::default::Default; #[derive(Debug, PartialEq, Deserialize, Serialize)] struct Query { #[serde(deserialize_with = "from_csv")] r: Vec<u8>, s: u8, } fn main() { let q = "s=12&r=1,2,3"; let q: Query = qs::from_str(q).unwrap(); println!("{:?}", q); } #[test] fn deserialize_sequence() { let q = "s=12&r=1,2,3"; let q: Query = qs::from_str(q).unwrap(); let expected = Query { r: vec![1, 2, 3], s: 12, }; assert_eq!(q, expected); } fn from_csv<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error> where D: serde::Deserializer<'de>, T: DeserializeOwned + std::str::FromStr, <T as std::str::FromStr>::Err: std::fmt::Debug, { deserializer.deserialize_str(CSVVecVisitor::<T>::default()) } /// Visits a string value of the form "v1,v2,v3" into a vector of bytes Vec<u8> struct CSVVecVisitor<T: DeserializeOwned + std::str::FromStr>(std::marker::PhantomData<T>); impl<T: DeserializeOwned + std::str::FromStr> Default for CSVVecVisitor<T> { fn default() -> Self { CSVVecVisitor(std::marker::PhantomData) } } impl<'de, T: DeserializeOwned + std::str::FromStr> serde::de::Visitor<'de> for CSVVecVisitor<T> where <T as std::str::FromStr>::Err: std::fmt::Debug, // handle the parse error in a generic way { type Value = Vec<T>; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { write!(formatter, "a str") } fn visit_str<E>(self, s: &str) -> std::result::Result<Self::Value, E> where E: serde::de::Error, { // Treat the comma-separated string as a single record in a CSV. let mut rdr = csv::ReaderBuilder::new() .has_headers(false) .from_reader(s.as_bytes()); // Try to get the record and collect its values into a vector. let mut output = Vec::new(); for result in rdr.records() { match result { Ok(record) => { for field in record.iter() { output.push( field .parse::<T>() .map_err(|_| E::custom("Failed to parse field"))?, ); } } Err(e) => { return Err(E::custom(format!( "could not deserialize sequence value: {:?}", e ))); } } } Ok(output) } }