114 lines
3.9 KiB
Rust
114 lines
3.9 KiB
Rust
use clap::{Parser, ValueEnum};
|
||
use serde::de::Deserializer;
|
||
use std::io::{Read, Write};
|
||
|
||
#[derive(Parser)]
|
||
#[clap(author, version, about, long_about = None)]
|
||
pub struct Opt {
|
||
/// Input type
|
||
#[clap(value_enum, ignore_case = true)]
|
||
pub input: Input,
|
||
/// Output type
|
||
#[clap(value_enum, ignore_case = true)]
|
||
pub output: Output,
|
||
|
||
/// For data format compatible, a default pretty format is output instead of a minified one
|
||
/// Output a pretty formated data instead of minified, only for format compatible
|
||
#[clap(long, short)]
|
||
pub pretty: bool,
|
||
/// Do not output a newline at the end of the stream
|
||
#[clap(long, short)]
|
||
pub no_newline: bool,
|
||
}
|
||
|
||
#[derive(Copy, Clone, Debug, ValueEnum)]
|
||
pub enum Input {
|
||
Json,
|
||
Ron,
|
||
Yaml,
|
||
}
|
||
|
||
#[derive(Copy, Clone, Debug, ValueEnum)]
|
||
pub enum Output {
|
||
Json,
|
||
Ron,
|
||
Yaml,
|
||
}
|
||
|
||
pub fn transcode(opt: Opt, input: &mut dyn Read, output: &mut dyn Write) {
|
||
// A JSON deserializer. You can use any Serde Deserializer here.
|
||
|
||
de(&opt, input, output);
|
||
|
||
// TODO: I would love to be able to have `de` and `ser` return the correct
|
||
// (de)serializer and then call `serde_transcode::transcode(deserializer, serializer)`
|
||
// here once for all. This will be a clearer separation of function,
|
||
// but it may need `erased_serde` that I did not made it work with `serde_transcode`.
|
||
|
||
if !opt.no_newline {
|
||
output.write_all(b"\n").expect(
|
||
"We already wrote the whole serialized struct, a new line at the end should be OK",
|
||
);
|
||
}
|
||
}
|
||
|
||
fn de(opt: &Opt, input: &mut dyn Read, output: &mut dyn Write) {
|
||
match opt.input {
|
||
Input::Json => {
|
||
// NOTE: Apparently serde_json do not implement `Deserializer` on const?
|
||
let mut deserializer = serde_json::Deserializer::from_reader(input);
|
||
ser(opt, &mut deserializer, output);
|
||
}
|
||
Input::Ron => {
|
||
// NOTE: Apparently ron do not implement `Deserializer` on const?
|
||
// NOTE: Apparently ron do not implement `Deserializer::from_reader` but it can serialise into a writter…
|
||
let mut buf = vec![];
|
||
let _buf_size = input.read_to_end(&mut buf).unwrap();
|
||
let mut deserializer = ron::Deserializer::from_bytes(&buf).unwrap();
|
||
ser(opt, &mut deserializer, output);
|
||
}
|
||
Input::Yaml => {
|
||
let deserializer = serde_yaml::Deserializer::from_reader(input);
|
||
ser(opt, deserializer, output);
|
||
}
|
||
};
|
||
}
|
||
|
||
fn ser<'de, D>(opt: &Opt, deserializer: D, output: &mut dyn Write)
|
||
where
|
||
D: Deserializer<'de>,
|
||
{
|
||
match opt.output {
|
||
Output::Json => {
|
||
if opt.pretty {
|
||
let formatter = serde_json::ser::PrettyFormatter::with_indent(b"\t");
|
||
let serializer = &mut serde_json::Serializer::with_formatter(output, formatter);
|
||
|
||
serde_transcode::transcode(deserializer, serializer).unwrap();
|
||
} else {
|
||
let serializer = &mut serde_json::Serializer::new(output);
|
||
|
||
serde_transcode::transcode(deserializer, serializer).unwrap();
|
||
};
|
||
|
||
// NOTE: serde_json’s PrettyFormatter and CompactFormatter are incompatibles…
|
||
// serde_transcode::transcode(deserializer, serializer).unwrap();
|
||
}
|
||
Output::Ron => {
|
||
let mut pretty_config = None;
|
||
if opt.pretty {
|
||
let pretty = ron::ser::PrettyConfig::new().indentor("\t".to_owned());
|
||
pretty_config = Some(pretty);
|
||
}
|
||
let serializer = &mut ron::Serializer::new(output, pretty_config).unwrap();
|
||
|
||
serde_transcode::transcode(deserializer, serializer).unwrap();
|
||
}
|
||
Output::Yaml => {
|
||
let serializer = &mut serde_yaml::Serializer::new(output);
|
||
|
||
serde_transcode::transcode(deserializer, serializer).unwrap();
|
||
}
|
||
};
|
||
}
|