use std::{
fmt::Debug,
io::{Read, Write},
};
use error_stack::{report, Report, ResultExt};
use rmp_serde::config::{DefaultConfig, StructMapConfig};
use serde_json::ser::PrettyFormatter;
use crate::Error;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConversionDirection {
Auto,
MsgPack2Json,
Json2MsgPack,
}
pub struct Converter<I, O> {
input: I,
output: O,
direction: ConversionDirection,
}
impl<I, O> Converter<I, O>
where
I: Read,
O: Write,
{
#[must_use]
pub fn new(input: I, output: O, direction: ConversionDirection) -> Self {
Self { input, output, direction }
}
pub fn execute(mut self) -> Result<(), Report<Error>> {
match self.direction {
ConversionDirection::Auto => self.automatic_conversion()?,
ConversionDirection::MsgPack2Json => {
let mut deserializer = msgpack_deserializer(self.input);
let mut serializer = json_serializer(&mut self.output);
serde_transcode::transcode(&mut deserializer, &mut serializer)
.change_context(Error::Transcoding)?;
}
ConversionDirection::Json2MsgPack => {
let mut deserializer = json_deserializer(self.input);
let mut serializer = msgpack_serializer(&mut self.output);
serde_transcode::transcode(&mut deserializer, &mut serializer)
.change_context(Error::Transcoding)?;
}
}
self.output.write(&[b'\n']).change_context(Error::FileWrite)?;
Ok(())
}
fn automatic_conversion(&mut self) -> Result<(), Report<Error>> {
let mut data = Vec::new();
self.input.read_to_end(&mut data).change_context(Error::FileRead)?;
let mut error = report!(Error::AutomaticDetection);
let mut output = Vec::new();
let mut deserializer = json_deserializer(data.as_slice());
let mut serializer = msgpack_serializer(&mut output);
let res = serde_transcode::transcode(&mut deserializer, &mut serializer)
.change_context(Error::Transcoding);
match res {
Ok(_) => return self.output.write_all(&output).change_context(Error::FileWrite),
Err(err) => error.extend_one(err),
}
drop(output);
let mut deserializer = msgpack_deserializer(data.as_slice());
let mut serializer = json_serializer(&mut self.output);
let res = serde_transcode::transcode(&mut deserializer, &mut serializer)
.change_context(Error::Transcoding);
match res {
Ok(_) => return Ok(()),
Err(err) => error.extend_one(err),
}
Err(error)
}
}
fn msgpack_deserializer<R: Read>(
reader: R,
) -> rmp_serde::Deserializer<rmp_serde::decode::ReadReader<R>> {
rmp_serde::Deserializer::new(reader)
}
fn msgpack_serializer<W: Write>(
writer: W,
) -> rmp_serde::Serializer<W, StructMapConfig<DefaultConfig>> {
rmp_serde::Serializer::new(writer).with_struct_map()
}
fn json_deserializer<R: Read>(reader: R) -> serde_json::Deserializer<serde_json::de::IoRead<R>> {
serde_json::Deserializer::from_reader(reader)
}
fn json_serializer<W: Write>(writer: W) -> serde_json::Serializer<W, PrettyFormatter<'static>> {
serde_json::Serializer::pretty(writer)
}
impl<I, O> Debug for Converter<I, O> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Converter")
.field("input", &"<redacted>")
.field("output", &"<redacted>")
.field("direction", &self.direction)
.finish()
}
}