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(); } }; }