1use crate::prelude::{Context, Deserialize, Result, Serialize};
2use std::{
3 borrow::Borrow,
4 io::{Read, Write},
5};
6
7pub trait Format {
12 type Output<T>;
14 type Input<T>: ?Sized;
18
19 fn deserialise<T>(rdr: &mut dyn Read) -> Result<Self::Output<T>>
21 where
22 for<'de> T: Deserialize<'de>;
23
24 fn serialise<T>(wtr: &mut dyn Write, val: &Self::Input<T>) -> Result<()>
26 where
27 T: Serialize;
28}
29
30pub trait ReadAs {
64 fn read_as<F, T>(&mut self) -> Result<F::Output<T>>
66 where
67 F: Format,
68 for<'de> T: Deserialize<'de>;
69}
70
71impl<R: Read> ReadAs for R {
72 fn read_as<F, T>(&mut self) -> Result<F::Output<T>>
73 where
74 F: Format,
75 for<'de> T: Deserialize<'de>,
76 {
77 F::deserialise(self)
78 }
79}
80
81pub trait WriteAs<F, T> {
120 fn write_as(&self, fmt: F, wtr: &mut dyn Write) -> Result<()>;
122}
123
124impl<F, T, A> WriteAs<F, T> for A
125where
126 F: Format,
127 T: Serialize,
128 A: Borrow<F::Input<T>>,
129{
130 fn write_as(&self, _: F, wtr: &mut dyn Write) -> Result<()> {
131 F::serialise(wtr, self.borrow())
132 }
133}
134
135pub struct CSV;
140impl Format for CSV {
141 type Output<T> = Vec<T>;
142 type Input<T> = [T];
143
144 fn deserialise<T>(rdr: &mut dyn Read) -> Result<Self::Output<T>>
145 where
146 for<'de> T: Deserialize<'de>,
147 {
148 let mut v = Vec::new();
149 for r in ::csv::Reader::from_reader(rdr).into_deserialize() {
150 let r: T = r?;
151 v.push(r);
152 }
153
154 Ok(v)
155 }
156
157 fn serialise<T>(wtr: &mut dyn Write, val: &[T]) -> Result<()>
158 where
159 T: Serialize,
160 {
161 let mut csv = ::csv::Writer::from_writer(wtr);
162 for x in val {
163 csv.serialize(x)?;
164 }
165
166 Ok(())
167 }
168}
169
170pub struct JSON;
175impl Format for JSON {
176 type Output<T> = T;
177 type Input<T> = T;
178
179 fn deserialise<T>(rdr: &mut dyn Read) -> Result<Self::Output<T>>
180 where
181 for<'de> T: Deserialize<'de>,
182 {
183 serde_json::from_reader(rdr).with_context(|| {
184 format!(
185 "failed to deserialise {} from JSON",
186 std::any::type_name::<T>()
187 )
188 })
189 }
190
191 fn serialise<T>(wtr: &mut dyn Write, val: &T) -> Result<()>
192 where
193 T: Serialize,
194 {
195 serde_json::to_writer_pretty(wtr, &val)
196 .with_context(|| format!("failed to serialise {} as JSON", std::any::type_name::<T>()))
197 }
198}
199
200pub struct TOML;
205impl Format for TOML {
206 type Output<T> = T;
207 type Input<T> = T;
208
209 fn deserialise<T>(rdr: &mut dyn Read) -> Result<Self::Output<T>>
210 where
211 for<'de> T: Deserialize<'de>,
212 {
213 let mut s = String::new();
214 rdr.read_to_string(&mut s)
215 .context("failed reading TOML data to string")?;
216
217 toml::from_str(&s).with_context(|| {
218 format!(
219 "failed to deserialise {} from TOML",
220 std::any::type_name::<T>()
221 )
222 })
223 }
224
225 fn serialise<T>(wtr: &mut dyn Write, val: &T) -> Result<()>
226 where
227 T: Serialize,
228 {
229 let s = toml::to_string_pretty(val).with_context(|| {
230 format!("failed to serialise {} as TOML", std::any::type_name::<T>())
231 })?;
232
233 wtr.write_all(s.as_bytes())
234 .context("failed to write TOML to writer")
235 }
236}
237
238#[cfg(test)]
239mod tests {
240 use super::*;
241
242 #[derive(Serialize, Deserialize, Debug, PartialEq)]
243 struct City {
244 city: String,
245 pop: u32,
246 }
247
248 #[test]
249 fn structured_api_csv() {
250 let csv = "city,pop\nBrisbane,100000\nSydney,200000\n";
251
252 let x = csv.as_bytes().read_as::<CSV, City>().unwrap();
253
254 assert_eq!(
255 x,
256 vec![
257 City {
258 city: "Brisbane".to_string(),
259 pop: 100_000,
260 },
261 City {
262 city: "Sydney".to_string(),
263 pop: 200_000,
264 }
265 ]
266 );
267
268 let mut buf = Vec::new();
269 x.as_slice().write_as(CSV, &mut buf).unwrap();
270
271 assert_eq!(buf, csv.as_bytes());
272
273 let mut buf = Vec::new();
275 x.write_as(CSV, &mut buf).unwrap();
276
277 assert_eq!(buf, csv.as_bytes());
278 }
279
280 #[test]
281 fn structured_api_json() {
282 let data = serde_json::json!({
283 "city": "Brisbane",
284 "pop": 100_000
285 });
286
287 let x = data.to_string().as_bytes().read_as::<JSON, City>().unwrap();
288
289 assert_eq!(
290 x,
291 City {
292 city: "Brisbane".to_string(),
293 pop: 100_000,
294 }
295 );
296
297 let mut buf = Vec::new();
298 x.write_as(JSON, &mut buf).unwrap();
299
300 assert_eq!(
301 buf,
302 r#"{
303 "city": "Brisbane",
304 "pop": 100000
305}"#
306 .as_bytes()
307 );
308 }
309}