183 lines
6.1 KiB
Rust
183 lines
6.1 KiB
Rust
use clap::{Parser, ValueEnum};
|
||
use serde::de::Deserializer;
|
||
use std::io::{Read, Write};
|
||
|
||
#[derive(Debug, 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 {
|
||
//Bson,
|
||
//Cbor,
|
||
Json,
|
||
Json5,
|
||
Pickle,
|
||
Ron,
|
||
//Toml
|
||
Yaml,
|
||
}
|
||
|
||
#[derive(Copy, Clone, Debug, ValueEnum)]
|
||
pub enum Output {
|
||
//Bson,
|
||
//Cbor,
|
||
Json,
|
||
//Json5, // NOTE: The crate is not notted "(deserialization only)" on the [serde listing](https://serde.rs/#data-formats) but it does not expose a serializer
|
||
Pickle,
|
||
Ron,
|
||
//Toml,
|
||
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::Bson => {
|
||
use bson::Deserializer;
|
||
|
||
let mut deserializer = bson::from_reader(input).unwrap(); // FIXME: need which type annotation?
|
||
ser(opt, &mut deserializer, output);
|
||
}
|
||
*/
|
||
Input::Json => {
|
||
use serde_json::Deserializer;
|
||
|
||
// NOTE: Apparently serde_json do not implement `Deserializer` on const?
|
||
let mut deserializer = Deserializer::from_reader(input);
|
||
ser(opt, &mut deserializer, output);
|
||
}
|
||
Input::Json5 => {
|
||
use json5::Deserializer;
|
||
|
||
// NOTE: Apparently Json5 do not implement `Deserializer` on const?
|
||
// NOTE: Apparently Json5 do not implement `Deserializer::from_reader` but it can serialise into a writter…
|
||
let mut buf = String::new();
|
||
let _buf_size = input.read_to_string(&mut buf).unwrap();
|
||
let mut deserializer = Deserializer::from_str(&buf).unwrap();
|
||
ser(opt, &mut deserializer, output);
|
||
}
|
||
Input::Pickle => {
|
||
use serde_pickle::Deserializer;
|
||
|
||
// NOTE: Apparently serde_pickle do not implement `Deserializer` on const?
|
||
let mut deserializer = Deserializer::new(input, serde_pickle::DeOptions::new());
|
||
ser(opt, &mut deserializer, output);
|
||
}
|
||
Input::Ron => {
|
||
use ron::Deserializer;
|
||
|
||
// 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 = Deserializer::from_bytes(&buf).unwrap();
|
||
ser(opt, &mut deserializer, output);
|
||
}
|
||
Input::Yaml => {
|
||
use serde_yaml::Deserializer;
|
||
|
||
let deserializer = 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::Bson => {
|
||
use bson::Serializer;
|
||
|
||
let options = bson::SerializerOptions::builder();
|
||
let options = if opt.pretty {
|
||
options.human_readable(true)
|
||
} else {
|
||
options.human_readable(false)
|
||
};
|
||
|
||
let serializer = Serializer::new_with_options(options.build()); // FIXME: why no way to tell the serializer were we want the output?
|
||
serde_transcode::transcode(deserializer, serializer).unwrap();
|
||
}
|
||
*/
|
||
Output::Json => {
|
||
use serde_json::Serializer;
|
||
|
||
if opt.pretty {
|
||
let formatter = serde_json::ser::PrettyFormatter::with_indent(b"\t");
|
||
let serializer = &mut Serializer::with_formatter(output, formatter);
|
||
|
||
serde_transcode::transcode(deserializer, serializer).unwrap();
|
||
} else {
|
||
let serializer = &mut 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::Pickle => {
|
||
use serde_pickle::Serializer;
|
||
|
||
let serializer = &mut Serializer::new(output, serde_pickle::SerOptions::new());
|
||
|
||
serde_transcode::transcode(deserializer, serializer).unwrap();
|
||
}
|
||
Output::Ron => {
|
||
use ron::Serializer;
|
||
|
||
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 Serializer::new(output, pretty_config).unwrap();
|
||
|
||
serde_transcode::transcode(deserializer, serializer).unwrap();
|
||
}
|
||
Output::Yaml => {
|
||
use serde_yaml::Serializer;
|
||
|
||
let serializer = &mut Serializer::new(output);
|
||
|
||
serde_transcode::transcode(deserializer, serializer).unwrap();
|
||
}
|
||
};
|
||
}
|