summaryrefslogtreecommitdiff
path: root/examples/csv_vectors.rs
diff options
context:
space:
mode:
Diffstat (limited to 'examples/csv_vectors.rs')
-rw-r--r--examples/csv_vectors.rs56
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)