diff options
Diffstat (limited to 'examples/csv_vectors.rs')
-rw-r--r-- | examples/csv_vectors.rs | 56 |
1 files changed, 44 insertions, 12 deletions
diff --git a/examples/csv_vectors.rs b/examples/csv_vectors.rs index c193c64..2e44566 100644 --- a/examples/csv_vectors.rs +++ b/examples/csv_vectors.rs @@ -3,12 +3,10 @@ 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, Deserialize, Serialize)] +#[derive(Debug, PartialEq, Deserialize, Serialize)] struct Query { #[serde(deserialize_with = "from_csv")] r: Vec<u8>, @@ -21,24 +19,39 @@ fn main() { 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, + 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::marker::PhantomData<T>); +struct CSVVecVisitor<T: DeserializeOwned + std::str::FromStr>(std::marker::PhantomData<T>); -impl<T: DeserializeOwned> Default for CSVVecVisitor<T> { +impl<T: DeserializeOwned + std::str::FromStr> Default for CSVVecVisitor<T> { fn default() -> Self { CSVVecVisitor(std::marker::PhantomData) } } -impl<'de, T: DeserializeOwned> serde::de::Visitor<'de> for CSVVecVisitor<T> { +impl<T: DeserializeOwned + std::str::FromStr> serde::de::Visitor<'_> 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 { @@ -49,12 +62,31 @@ impl<'de, T: DeserializeOwned> serde::de::Visitor<'de> for CSVVecVisitor<T> { 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(); - let mut items = csv::Reader::from_reader(s.as_bytes()); - for res in items.deserialize() { - let item: T = res - .map_err(|e| E::custom(format!("could not deserialize sequence value: {:?}", e)))?; - output.push(item); + 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) |