tradaf 0.1.1

Tranduit Data Format: Translate serialized data from one format to another.
Documentation
use clap::{Parser, ValueEnum};
use serde::de::Deserializer;
use std::{
    convert::TryFrom,
    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,

    #[clap(long, short = 'F', required_if_eq_any(&[("input", "d-bus"), ("input", "g-variant")]))]
    pub format_in: Option<String>,
    #[clap(long, short = 'f', required_if_eq_any(&[("output", "d-bus"), ("output", "g-variant")]))]
    pub format_out: Option<String>,

    /// 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 {
    Bencode,
    //Bson,
    //Cbor,
    DBus,
    //DynamoDB,
    //FlexBuffer,
    GVariant,
    Json,
    Json5,
    //SExpression,
    Pickle,
    //Qs,   // NOTE: The crate is not noted "(serialization only)" on the [serde listing](https://serde.rs/#data-formats) but it does not expose a `Deserializer`
    //Rmp,  // NOTE: It appears that we are forced to deserialize into a concrete type
    Ron,
    //Toml
    Yaml,
}

#[derive(Copy, Clone, Debug, ValueEnum)]
pub enum Output {
    //Bencode,
    //Bson,
    //Cbor,
    DBus,
    //DynamoDB,
    //FlexBuffer,
    GVariant,
    Json,
    //Json5,    // NOTE: The crate is not noted "(deserialization only)" on the [serde listing](https://serde.rs/#data-formats) but it does not expose a `Serializer`
    //SExpression,
    Pickle,
    Qs,
    Rmp,
    Ron,
    //Toml,
    Yaml,
}

pub fn transcode(opt: Opt, input: &mut dyn Read, output: &mut dyn Write) {
    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::Bencode => {
            use bendy::serde::Deserializer;

            let mut buf = vec![];
            let _buf_size = input.read_to_end(&mut buf).unwrap();
            let mut deserializer = Deserializer::from_bytes(&buf);
            ser(opt, &mut deserializer, output);
        }
        /*
        Input::Bson => {
            use bson::Deserializer;

            let deserializer = bson::from_reader(input).unwrap();    // FIXME: can we skip the type annotation?
            ser(opt, deserializer, output);
        }
        */
        Input::DBus => {
            use zvariant::dbus::Deserializer;
            use zvariant::EncodingContext;
            use zvariant::Signature;

            use byteorder::LE;

            let sig = opt.format_in.clone().unwrap();
            let mut buf = String::new();
            let _buf_size = input.read_to_string(&mut buf).unwrap();
            let mut deserializer = Deserializer::new(
                buf.as_bytes(),
                None,
                &Signature::try_from(sig).unwrap(),
                EncodingContext::<LE>::new_dbus(0),
            );
            ser(opt, &mut deserializer, output);
        }
        /*
        Input::DynamoDB => {
            use serde_dynamo::Deserializer;

            let deserializer = Deserializer::from(input); // from_reader(input);
            ser(opt, deserializer, output);
        }
        */
        /*
        Input::FlexBuffer => {
            use serde_yaml::Deserializer;

            let deserializer = Deserializer::from_reader(input);
            ser(opt, deserializer, output);
        }
        */
        Input::GVariant => {
            use zvariant::gvariant::Deserializer;
            use zvariant::EncodingContext;
            use zvariant::Signature;

            use byteorder::LE;

            let sig = opt.format_in.clone().unwrap();
            let mut buf = String::new();
            let _buf_size = input.read_to_string(&mut buf).unwrap();
            let mut deserializer = Deserializer::new(
                buf.as_bytes(),
                None,
                &Signature::try_from(sig).unwrap(),
                EncodingContext::<LE>::new_dbus(0),
            );
            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::SExpression => {
            use serde_lexpr as Deserializer;

            let deserializer = Deserializer::from_reader(input).unwrap();    // FIXME: can we skip the type annotation?
            ser(opt, 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::Bencode => {
            use bendy::serde::Serializer;

            let serializer = &mut Serializer::new(/*output*/);

            serde_transcode::transcode(deserializer, serializer).unwrap();
            serializer.into_bytes();
        }
        */
        /*
        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::DBus => {
            use zvariant::dbus::Serializer;
            use zvariant::EncodingContext;
            use zvariant::Signature;

            use byteorder::LE;

            let sig = opt.format_out.clone().unwrap();
            let mut out = std::io::Cursor::new(vec![]);
            let mut fs = vec![];
            let serializer = &mut Serializer::new(
                &Signature::try_from(sig).unwrap(),
                &mut out,
                &mut fs, //None,
                EncodingContext::<LE>::new_dbus(0),
            );

            //let mut buf = String::new();
            //           let _buf_size = output.read_to_string(&mut buf).unwrap();
            //            let mut deserializer = Deserializer::new();
            serde_transcode::transcode(deserializer, serializer).unwrap();
        }
        /*
        Output::DynamoDB => {
            use serde_dynamo::Serializer;

            let serializer = &mut Serializer::new(output);

            serde_transcode::transcode(deserializer, serializer).unwrap();
        }
        */
        /*
        Output::FlexBuffer => {
            use flexbuffers::FlexbufferSerializer as Serializer;

            let serializer = &mut Serializer::new(/*output*/);

            // serde_transcode::transcode(deserializer, serializer).unwrap();
            let r = flexbuffers::Reader::get_root(serializer.view()).unwrap();
            println!("{}", r);
        }
        */
        Output::GVariant => {
            use zvariant::gvariant::Serializer;
            use zvariant::EncodingContext;
            use zvariant::Signature;

            use byteorder::LE;

            let sig = opt.format_out.clone().unwrap();
            let mut out = std::io::Cursor::new(vec![]);
            let mut fs = vec![];
            let serializer = &mut Serializer::new(
                &Signature::try_from(sig).unwrap(),
                &mut out,
                &mut fs, //None,
                EncodingContext::<LE>::new_dbus(0),
            );

            //let mut buf = String::new();
            //           let _buf_size = output.read_to_string(&mut buf).unwrap();
            //            let mut deserializer = Deserializer::new();
            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::SExpression => {
            use serde_lexpr::to_writer as Serializer;

            let serializer = Serializer::new(output);    // FIXME: There is a `to_writer` but the Serializer is not exposed directly.
            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::Qs => {
            use serde_qs::Serializer;

            let serializer = &mut Serializer::new(output);

            serde_transcode::transcode(deserializer, serializer).unwrap();
        }
        Output::Rmp => {
            use rmp_serde::Serializer;

            let serializer = &mut Serializer::new(output);

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