itch/
lib.rs

1use indexmap::IndexMap;
2use serde::{Deserialize, Serialize};
3
4#[derive(Serialize, Deserialize)]
5#[serde(untagged)]
6enum Itch {
7    Obj(IndexMap<String, Itch>),
8    Array(Vec<Itch>),
9    Bool(bool),
10    Int(i64),
11    Float(f64),
12    Text(String),
13}
14
15#[derive(Clone, Debug)]
16pub enum FromType {
17    Json,
18    Toml,
19    Url,
20    Yaml,
21    Xml,
22    Cbor,
23}
24
25impl std::str::FromStr for FromType {
26    type Err = String;
27
28    fn from_str(s: &str) -> Result<Self, Self::Err> {
29        match s {
30            "cbor" => Ok(Self::Cbor),
31            "json" => Ok(Self::Json),
32            "qs" => Ok(Self::Url),
33            "toml" => Ok(Self::Toml),
34            "url" => Ok(Self::Url),
35            "xml" => Ok(Self::Xml),
36            "yaml" => Ok(Self::Yaml),
37            "yml" => Ok(Self::Yaml),
38            _ => Err(format!("could not parse `{}` as an input type", s)),
39        }
40    }
41}
42
43#[derive(Clone, Debug)]
44pub enum ToType {
45    Json,
46    Toml,
47    Url,
48    Yaml,
49    Xml,
50    Cbor,
51}
52
53impl std::str::FromStr for ToType {
54    type Err = String;
55
56    fn from_str(s: &str) -> Result<Self, Self::Err> {
57        match s {
58            "cbor" => Ok(Self::Cbor),
59            "json" => Ok(Self::Json),
60            "qs" => Ok(Self::Url),
61            "toml" => Ok(Self::Toml),
62            "url" => Ok(Self::Url),
63            "xml" => Ok(Self::Xml),
64            "yaml" => Ok(Self::Yaml),
65            _ => Err(format!("could not parse `{}` as an output type", s)),
66        }
67    }
68}
69
70pub fn convert<From: std::io::Read, To: std::io::Write>(
71    from_type: &FromType,
72    to_type: &ToType,
73    mut input: From,
74    mut output: To,
75) -> Result<(), String> {
76    let itch: Itch =
77        match from_type {
78            FromType::Json => serde_json::from_reader(input)
79                .map_err(|e| format!("error parsing json: `{}`", e))?,
80
81            FromType::Xml => serde_xml_rs::from_reader(input)
82                .map_err(|e| format!("error parsing xml: `{}`", e))?,
83
84            FromType::Yaml => serde_yaml::from_reader(input)
85                .map_err(|e| format!("error parsing yaml: `{}`", e))?,
86
87            FromType::Toml => {
88                let mut s = String::new();
89                input
90                    .read_to_string(&mut s)
91                    .map_err(|e| format!("error parsing toml: `{}`", e))?;
92                toml::from_str(&s).map_err(|e| format!("error parsing toml: `{}`", e))?
93            }
94
95            FromType::Url => {
96                let mut s = String::new();
97                input
98                    .read_to_string(&mut s)
99                    .map_err(|e| format!("error parsing url query string: `{}`", e))?;
100                serde_qs::from_str(&s)
101                    .map_err(|e| format!("error parsing url query string: `{}`", e))?
102            }
103
104            FromType::Cbor => {
105                serde_cbor::from_reader(input).map_err(|e| format!("error parsing cbor `{}`", e))?
106            }
107        };
108
109    match to_type {
110        ToType::Json => serde_json::to_writer(output, &itch).map_err(|e| {
111            dbg!(&e);
112            format!("error outputting json: `{}`", e)
113        })?,
114
115        ToType::Url => serde_qs::to_writer(&itch, &mut output)
116            .map_err(|e| format!("error outputting url query string: `{}`", e))?,
117
118        ToType::Xml => serde_xml_rs::to_writer(output, &itch)
119            .map_err(|e| format!("error outputting xml: `{}`", e))?,
120
121        ToType::Yaml => serde_yaml::to_writer(output, &itch)
122            .map_err(|e| format!("error outputting yaml: `{}`", e))?,
123
124        ToType::Toml => {
125            let s = toml::to_string_pretty(&itch)
126                .map_err(|e| format!("error outputting toml: `{}`", e))?;
127            output
128                .write(s.as_bytes())
129                .map(|_| ())
130                .map_err(|e| format!("error outputting toml: `{}`", e))?
131        }
132
133        ToType::Cbor => serde_cbor::to_writer(output, &itch)
134            .map_err(|e| format!("error outputing cbor `{}`", e))?,
135    };
136
137    Ok(())
138}