serde_csv_extra/
lib.rs

1//! Csv-related serde addons
2//!
3//! ```rust
4//! use serde::{Deserialize, Serialize};
5//!
6//! #[derive(Deserialize, Serialize)]
7//! struct Foo {
8//!    #[serde(with = "serde_csv_extra::vec_num")]
9//!    list: Vec<i32>,
10//!    #[serde(with = "serde_csv_extra::vec_vec_num")]
11//!    matrix: Vec<Vec<i32>>,
12//!    #[serde(with = "serde_csv_extra::maybe_image_size")]
13//!    image_size: Option<(u8, u16)>,
14//!    #[serde(with = "serde_csv_extra::maybe_lat_lon")]
15//!    geo: Option<(f32, f32)>,
16//! }
17//!
18//! let mut wtr = csv::WriterBuilder::new().has_headers(false).from_writer(Vec::new());
19//! wtr.serialize(
20//!     Foo {
21//!         list: vec![-1, 1],
22//!         matrix: vec![vec![-1, 1], vec![1, -1]],
23//!         image_size: Some((16, 1024)),
24//!         geo: Some((84.99, -135.00)),
25//!     }
26//! ).unwrap();
27//! wtr.serialize(
28//!     Foo {
29//!         list: vec![],
30//!         matrix: vec![],
31//!         image_size: None,
32//!         geo: None,
33//!     }
34//! ).unwrap();
35//! let s = String::from_utf8(wtr.into_inner().unwrap()).unwrap();
36//! assert_eq!(s, "-1_1,-1_1|1_-1,16x1024,84.99;-135\n,,,\n");
37//! ```
38
39#![warn(clippy::all, missing_docs, nonstandard_style, future_incompatible)]
40
41/// `&[-1, 1]` <--> `-1_1`
42pub mod vec_num {
43    use serde::{self, de::Error, Deserialize, Deserializer, Serializer};
44    use std::{fmt::Display, str::FromStr};
45
46    /// Serializer
47    pub fn serialize<S, T>(list: &[T], serializer: S) -> Result<S::Ok, S::Error>
48    where
49        S: Serializer,
50        T: ToString,
51    {
52        let s = list
53            .iter()
54            .map(ToString::to_string)
55            .collect::<Vec<_>>()
56            .join("_");
57        serializer.serialize_str(&s)
58    }
59
60    /// Deserializer
61    pub fn deserialize<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
62    where
63        D: Deserializer<'de>,
64        T: FromStr + Display,
65        <T as FromStr>::Err: Display,
66    {
67        let s = String::deserialize(deserializer)?;
68        if s.is_empty() {
69            return Ok(Vec::new());
70        }
71        s.split('_')
72            .map(|n| n.parse().map_err(Error::custom))
73            .collect()
74    }
75}
76
77/// `&[[vec![-1, 1], vec![1, -1]]` <--> `-1_1|1_-1`
78pub mod vec_vec_num {
79    use serde::{self, Deserialize, Deserializer, Serializer};
80    use std::{fmt::Display, str::FromStr};
81
82    /// Serializer
83    pub fn serialize<S, T>(rows: &[Vec<T>], serializer: S) -> Result<S::Ok, S::Error>
84    where
85        S: Serializer,
86        T: ToString,
87    {
88        let s = rows
89            .iter()
90            .map(|c| {
91                c.iter()
92                    .map(ToString::to_string)
93                    .collect::<Vec<_>>()
94                    .join("_")
95            })
96            .collect::<Vec<_>>()
97            .join("|");
98        serializer.serialize_str(&s)
99    }
100
101    /// Deserializer
102    pub fn deserialize<'de, D, T>(deserializer: D) -> Result<Vec<Vec<T>>, D::Error>
103    where
104        D: Deserializer<'de>,
105        T: FromStr + Display,
106        <T as FromStr>::Err: Display,
107    {
108        let s = String::deserialize(deserializer)?;
109        if s.is_empty() {
110            return Ok(Vec::new());
111        }
112
113        let mut rows = Vec::new();
114        for line in s.split('|') {
115            let mut row = Vec::new();
116            for col_str in line.split('_') {
117                row.push(col_str.parse().map_err(serde::de::Error::custom)?)
118            }
119            rows.push(row);
120        }
121
122        Ok(rows)
123    }
124}
125
126/// `Some((128, 64))` <--> `128x64`
127pub mod maybe_image_size {
128    use serde::{self, de::Error, Deserialize, Deserializer, Serializer};
129    use std::{fmt::Display, str::FromStr};
130
131    /// Serializer
132    pub fn serialize<S, W, H>(size: &Option<(W, H)>, serializer: S) -> Result<S::Ok, S::Error>
133    where
134        S: Serializer,
135        W: Display,
136        H: Display,
137    {
138        if let Some(size) = size {
139            let s = format!("{}x{}", size.0, size.1);
140            serializer.serialize_str(&s)
141        } else {
142            serializer.serialize_str("")
143        }
144    }
145
146    /// Deserializer
147    pub fn deserialize<'de, D, W, H>(deserializer: D) -> Result<Option<(W, H)>, D::Error>
148    where
149        D: Deserializer<'de>,
150        W: FromStr + Display,
151        <W as FromStr>::Err: Display,
152        H: FromStr + Display,
153        <H as FromStr>::Err: Display,
154    {
155        let s = String::deserialize(deserializer)?;
156        if s.is_empty() {
157            return Ok(None);
158        }
159        let (width, height) = s
160            .split_once("x")
161            .ok_or_else(|| Error::custom("bad image size format"))?;
162        Ok(Some((
163            width.parse().map_err(Error::custom)?,
164            height.parse().map_err(Error::custom)?,
165        )))
166    }
167}
168
169/// `Some((84.99, -135.00))` <--> `84.99;-135.00`
170pub mod maybe_lat_lon {
171    use serde::{self, de::Error, Deserialize, Deserializer, Serializer};
172    use std::{fmt::Display, str::FromStr};
173
174    /// Serializer
175    pub fn serialize<S, T>(size: &Option<(T, T)>, serializer: S) -> Result<S::Ok, S::Error>
176    where
177        S: Serializer,
178        T: Display,
179    {
180        if let Some(size) = size {
181            let s = format!("{};{}", size.0, size.1);
182            serializer.serialize_str(&s)
183        } else {
184            serializer.serialize_str("")
185        }
186    }
187
188    /// Deserializer
189    pub fn deserialize<'de, D, T>(deserializer: D) -> Result<Option<(T, T)>, D::Error>
190    where
191        D: Deserializer<'de>,
192        T: FromStr + Display,
193        <T as FromStr>::Err: Display,
194    {
195        let s = String::deserialize(deserializer)?;
196        if s.is_empty() {
197            return Ok(None);
198        }
199        let (lat, lon) = s
200            .split_once(";")
201            .ok_or_else(|| Error::custom("bad image size format"))?;
202        Ok(Some((
203            lat.parse().map_err(Error::custom)?,
204            lon.parse().map_err(Error::custom)?,
205        )))
206    }
207}
208
209#[cfg(test)]
210mod tests {
211    use super::*;
212    use serde::{Deserialize, Serialize};
213
214    #[test]
215    fn vec_i32() {
216        #[derive(Debug, Deserialize, Serialize, PartialEq)]
217        struct Foo(#[serde(with = "vec_num")] Vec<i32>);
218
219        let foo = Foo(vec![-1, 0, 3]);
220        let foo_str = "\"-1_0_3\"";
221
222        let serialized = serde_json::to_string(&foo).unwrap();
223        assert_eq!(serialized, foo_str);
224
225        let deserialized: Foo = serde_json::from_str(foo_str).unwrap();
226        assert_eq!(deserialized, foo);
227
228        let empty = Foo(vec![]);
229        let empty_str = "\"\"";
230
231        let serialized = serde_json::to_string(&empty).unwrap();
232        assert_eq!(serialized, empty_str);
233
234        let deserialized: Foo = serde_json::from_str(empty_str).unwrap();
235        assert_eq!(deserialized, empty);
236    }
237
238    #[test]
239    fn vec_vec_i32() {
240        #[derive(Debug, Deserialize, Serialize, PartialEq)]
241        struct Foo(#[serde(with = "vec_vec_num")] Vec<Vec<i32>>);
242
243        let foo = Foo(vec![vec![0], vec![-1, 1]]);
244        let foo_str = "\"0|-1_1\"";
245
246        let serialized = serde_json::to_string(&foo).unwrap();
247        assert_eq!(serialized, foo_str);
248
249        let deserialized: Foo = serde_json::from_str(foo_str).unwrap();
250        assert_eq!(deserialized, foo);
251
252        let empty = Foo(vec![]);
253        let empty_str = "\"\"";
254
255        let serialized = serde_json::to_string(&empty).unwrap();
256        assert_eq!(serialized, empty_str);
257
258        let deserialized: Foo = serde_json::from_str(empty_str).unwrap();
259        assert_eq!(deserialized, empty);
260    }
261
262    #[test]
263    fn img_size() {
264        #[derive(Debug, Deserialize, Serialize, PartialEq)]
265        struct Foo(#[serde(with = "maybe_image_size")] Option<(u8, u16)>);
266
267        let foo = Foo(Some((1, 2)));
268        let foo_str = "\"1x2\"";
269
270        let serialized = serde_json::to_string(&foo).unwrap();
271        assert_eq!(serialized, foo_str);
272
273        let deserialized: Foo = serde_json::from_str(foo_str).unwrap();
274        assert_eq!(deserialized, foo);
275
276        let empty = Foo(None);
277        let empty_str = "\"\"";
278
279        let serialized = serde_json::to_string(&empty).unwrap();
280        assert_eq!(serialized, empty_str);
281
282        let deserialized: Foo = serde_json::from_str(empty_str).unwrap();
283        assert_eq!(deserialized, empty);
284    }
285
286    #[test]
287    fn geo() {
288        #[derive(Debug, Deserialize, Serialize, PartialEq)]
289        struct Foo(#[serde(with = "maybe_lat_lon")] Option<(f32, f32)>);
290
291        let foo = Foo(Some((-1.1, 1.1)));
292        let foo_str = "\"-1.1;1.1\"";
293
294        let serialized = serde_json::to_string(&foo).unwrap();
295        assert_eq!(serialized, foo_str);
296
297        let deserialized: Foo = serde_json::from_str(foo_str).unwrap();
298        assert_eq!(deserialized, foo);
299
300        let empty = Foo(None);
301        let empty_str = "\"\"";
302
303        let serialized = serde_json::to_string(&empty).unwrap();
304        assert_eq!(serialized, empty_str);
305
306        let deserialized: Foo = serde_json::from_str(empty_str).unwrap();
307        assert_eq!(deserialized, empty);
308    }
309}