record_query/value/
csv.rs

1use crate::error;
2use crate::value;
3use csv;
4use ordered_float;
5use std::fmt;
6use std::io;
7
8pub struct Source<R>(csv::StringRecordsIntoIter<R>)
9where
10    R: io::Read;
11
12pub struct Sink<W>(csv::Writer<W>)
13where
14    W: io::Write;
15
16#[inline]
17pub fn source<R>(r: R) -> Source<R>
18where
19    R: io::Read,
20{
21    Source(
22        csv::ReaderBuilder::new()
23            .has_headers(false)
24            .from_reader(r)
25            .into_records(),
26    )
27}
28
29#[inline]
30pub fn sink<W>(w: W) -> Sink<W>
31where
32    W: io::Write,
33{
34    Sink(csv::Writer::from_writer(w))
35}
36
37impl<R> value::Source for Source<R>
38where
39    R: io::Read,
40{
41    #[inline]
42    fn read(&mut self) -> error::Result<Option<value::Value>> {
43        match self.0.next() {
44            Some(Ok(v)) => Ok(Some(value::Value::Sequence(
45                v.iter()
46                    .map(|s| value::Value::String(s.to_string()))
47                    .collect(),
48            ))),
49            Some(Err(e)) => Err(error::Error::from(e)),
50            None => Ok(None),
51        }
52    }
53}
54
55impl<W> value::Sink for Sink<W>
56where
57    W: io::Write,
58{
59    #[inline]
60    fn write(&mut self, value: value::Value) -> error::Result<()> {
61        match value {
62            value::Value::Sequence(seq) => {
63                let record: Vec<String> = seq
64                    .into_iter()
65                    .map(value_to_csv)
66                    .collect::<error::Result<Vec<_>>>()?;
67                self.0.write_record(record)?;
68                Ok(())
69            }
70            x => Err(error::Error::Format {
71                msg: format!("csv can only output sequences, got: {:?}", x),
72            }),
73        }
74    }
75}
76
77fn value_to_csv(value: value::Value) -> error::Result<String> {
78    match value {
79        value::Value::Unit => Err(error::Error::Format {
80            msg: "csv cannot output nested Unit".to_owned(),
81        }),
82        value::Value::Bool(v) => Ok(v.to_string()),
83
84        value::Value::I8(v) => Ok(v.to_string()),
85        value::Value::I16(v) => Ok(v.to_string()),
86        value::Value::I32(v) => Ok(v.to_string()),
87        value::Value::I64(v) => Ok(v.to_string()),
88
89        value::Value::U8(v) => Ok(v.to_string()),
90        value::Value::U16(v) => Ok(v.to_string()),
91        value::Value::U32(v) => Ok(v.to_string()),
92        value::Value::U64(v) => Ok(v.to_string()),
93
94        value::Value::F32(ordered_float::OrderedFloat(v)) => Ok(v.to_string()),
95        value::Value::F64(ordered_float::OrderedFloat(v)) => Ok(v.to_string()),
96
97        value::Value::Char(v) => Ok(v.to_string()),
98        value::Value::String(v) => Ok(v),
99        value::Value::Bytes(_) => Err(error::Error::Format {
100            msg: "csv cannot output nested bytes".to_owned(),
101        }),
102
103        value::Value::Sequence(_) => Err(error::Error::Format {
104            msg: "csv cannot output nested sequences".to_owned(),
105        }),
106        value::Value::Map(_) => Err(error::Error::Format {
107            msg: "csv cannot output nested maps".to_owned(),
108        }),
109    }
110}
111
112impl<R> fmt::Debug for Source<R>
113where
114    R: io::Read,
115{
116    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
117        f.debug_struct("CsvSource").finish()
118    }
119}
120
121impl<W> fmt::Debug for Sink<W>
122where
123    W: io::Write,
124{
125    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
126        f.debug_struct("CsvSink").finish()
127    }
128}