init
This commit is contained in:
commit
57ea88db79
19 changed files with 507 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
Cargo.lock
|
6
Cargo.toml
Normal file
6
Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[workspace]
|
||||||
|
members = [
|
||||||
|
"sercon-base",
|
||||||
|
"sercon-backends",
|
||||||
|
"sercon-cli",
|
||||||
|
]
|
12
rustfmt.toml
Normal file
12
rustfmt.toml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
unstable_features = true
|
||||||
|
binop_separator = "Back"
|
||||||
|
format_code_in_doc_comments = true
|
||||||
|
format_macro_matchers = true
|
||||||
|
format_strings = true
|
||||||
|
imports_layout = "HorizontalVertical"
|
||||||
|
match_block_trailing_comma = true
|
||||||
|
merge_imports = true
|
||||||
|
normalize_comments = true
|
||||||
|
use_field_init_shorthand = true
|
||||||
|
use_try_shorthand = true
|
||||||
|
wrap_comments = true
|
26
sercon-backends/Cargo.toml
Normal file
26
sercon-backends/Cargo.toml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
[package]
|
||||||
|
name = "sercon-backends"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
miette = "4.2"
|
||||||
|
sercon-base = { path = "../sercon-base" }
|
||||||
|
serde = "1.0"
|
||||||
|
serde-value = "0.7"
|
||||||
|
|
||||||
|
ciborium = "0.2.0"
|
||||||
|
hematite-nbt = "0.5.2"
|
||||||
|
ron = "0.7.0"
|
||||||
|
serde-lexpr = "0.1.2"
|
||||||
|
serde-xml-rs = "0.5.1"
|
||||||
|
serde_json = "1.0.79"
|
||||||
|
serde_yaml = "0.8.23"
|
||||||
|
toml = "0.5.8"
|
||||||
|
|
||||||
|
[dependencies.bincode]
|
||||||
|
default-features = false
|
||||||
|
features = ["std", "serde"]
|
||||||
|
version = "2.0.0-beta.3"
|
20
sercon-backends/src/backends.rs
Normal file
20
sercon-backends/src/backends.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
macro_rules! backends {
|
||||||
|
($($name:ident),* $(,)?) => ($(
|
||||||
|
mod $name;
|
||||||
|
pub use self::$name::*;
|
||||||
|
)*)
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_filetype_backend {
|
||||||
|
($type:ty, [$($ft:expr),* $(,)?]) => (
|
||||||
|
impl crate::FiletypeBackend for $type {
|
||||||
|
fn supported_filetypes(&self) -> Vec<String> {
|
||||||
|
vec![$(String::from($ft)),*]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_backend(&self) -> &dyn Backend { self }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
backends![bincode, cbor, json, nbt, ron, s_expression, toml, xml, yaml,];
|
30
sercon-backends/src/backends/bincode.rs
Normal file
30
sercon-backends/src/backends/bincode.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
use miette::{Context, IntoDiagnostic, bail};
|
||||||
|
use sercon_base::Backend;
|
||||||
|
use serde_value::Value;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct BincodeBackend;
|
||||||
|
|
||||||
|
impl Backend for BincodeBackend {
|
||||||
|
fn serialize(&self, out: &mut dyn Write, data: Value) -> miette::Result<()> {
|
||||||
|
let data = bincode::serde::encode_to_vec(
|
||||||
|
data,
|
||||||
|
bincode::config::standard().write_fixed_array_length(),
|
||||||
|
)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("bincode serialization error")?;
|
||||||
|
out.write_all(&data)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("error writing bincode data")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(&self, _data: &mut dyn Read) -> miette::Result<Value> {
|
||||||
|
bail!("Bincode does not support deserializing into any");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_filetype_backend!(BincodeBackend, ["bincode"]);
|
24
sercon-backends/src/backends/cbor.rs
Normal file
24
sercon-backends/src/backends/cbor.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
use miette::{Context, IntoDiagnostic};
|
||||||
|
use sercon_base::Backend;
|
||||||
|
use serde_value::Value;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct CborBackend;
|
||||||
|
|
||||||
|
impl Backend for CborBackend {
|
||||||
|
fn serialize(&self, out: &mut dyn Write, data: Value) -> miette::Result<()> {
|
||||||
|
ciborium::ser::into_writer(&data, out)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("CBOR serialization error")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(&self, data: &mut dyn Read) -> miette::Result<Value> {
|
||||||
|
ciborium::de::from_reader(data)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("CBOR deserialization error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_filetype_backend!(CborBackend, ["cbor"]);
|
24
sercon-backends/src/backends/json.rs
Normal file
24
sercon-backends/src/backends/json.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
use miette::{Context, IntoDiagnostic};
|
||||||
|
use sercon_base::Backend;
|
||||||
|
use serde_value::Value;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct JsonBackend;
|
||||||
|
|
||||||
|
impl Backend for JsonBackend {
|
||||||
|
fn serialize(&self, out: &mut dyn Write, data: Value) -> miette::Result<()> {
|
||||||
|
serde_json::to_writer_pretty(out, &data)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("JSON serialization error")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(&self, data: &mut dyn Read) -> miette::Result<Value> {
|
||||||
|
serde_json::from_reader(data)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("JSON deserialization error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_filetype_backend!(JsonBackend, ["json"]);
|
24
sercon-backends/src/backends/nbt.rs
Normal file
24
sercon-backends/src/backends/nbt.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
use miette::{Context, IntoDiagnostic};
|
||||||
|
use sercon_base::Backend;
|
||||||
|
use serde_value::Value;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct NbtBackend;
|
||||||
|
|
||||||
|
impl Backend for NbtBackend {
|
||||||
|
fn serialize(&self, out: &mut dyn Write, data: Value) -> miette::Result<()> {
|
||||||
|
nbt::to_writer(out, &data, None)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("NBT serialization error")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(&self, data: &mut dyn Read) -> miette::Result<Value> {
|
||||||
|
nbt::from_reader(data)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("NBT deserialization error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_filetype_backend!(NbtBackend, ["nbt"]);
|
25
sercon-backends/src/backends/ron.rs
Normal file
25
sercon-backends/src/backends/ron.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
use miette::{Context, IntoDiagnostic};
|
||||||
|
use ron::ser::PrettyConfig;
|
||||||
|
use sercon_base::Backend;
|
||||||
|
use serde_value::Value;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct RonBackend;
|
||||||
|
|
||||||
|
impl Backend for RonBackend {
|
||||||
|
fn serialize(&self, out: &mut dyn Write, data: Value) -> miette::Result<()> {
|
||||||
|
ron::ser::to_writer_pretty(out, &data, PrettyConfig::new().new_line("\n".to_string()))
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("RON serialization error")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(&self, data: &mut dyn Read) -> miette::Result<Value> {
|
||||||
|
ron::de::from_reader(data)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("RON deserialization error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_filetype_backend!(RonBackend, ["ron"]);
|
24
sercon-backends/src/backends/s_expression.rs
Normal file
24
sercon-backends/src/backends/s_expression.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
use miette::{Context, IntoDiagnostic};
|
||||||
|
use sercon_base::Backend;
|
||||||
|
use serde_value::Value;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct SExpressionBackend;
|
||||||
|
|
||||||
|
impl Backend for SExpressionBackend {
|
||||||
|
fn serialize(&self, out: &mut dyn Write, data: Value) -> miette::Result<()> {
|
||||||
|
serde_lexpr::to_writer(out, &data)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("S-Expression serialization error")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(&self, data: &mut dyn Read) -> miette::Result<Value> {
|
||||||
|
serde_lexpr::from_reader(data)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("S-Expression deserialization error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_filetype_backend!(SExpressionBackend, ["sexpr"]);
|
35
sercon-backends/src/backends/toml.rs
Normal file
35
sercon-backends/src/backends/toml.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
use miette::{Context, IntoDiagnostic};
|
||||||
|
use sercon_base::Backend;
|
||||||
|
use serde_value::Value;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct TomlBackend;
|
||||||
|
|
||||||
|
impl Backend for TomlBackend {
|
||||||
|
fn serialize(&self, out: &mut dyn Write, data: Value) -> miette::Result<()> {
|
||||||
|
let data = toml::to_string_pretty(&data)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("TOML serialization error")?;
|
||||||
|
|
||||||
|
out.write_all(data.as_bytes())
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("error writing TOML data")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(&self, data: &mut dyn Read) -> miette::Result<Value> {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
data.read_to_end(&mut buf)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("error reading TOML input")?;
|
||||||
|
|
||||||
|
toml::from_slice(&buf)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("TOML deserialization error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_filetype_backend!(TomlBackend, ["toml"]);
|
24
sercon-backends/src/backends/xml.rs
Normal file
24
sercon-backends/src/backends/xml.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
use miette::{Context, IntoDiagnostic};
|
||||||
|
use sercon_base::Backend;
|
||||||
|
use serde_value::Value;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct XmlBackend;
|
||||||
|
|
||||||
|
impl Backend for XmlBackend {
|
||||||
|
fn serialize(&self, out: &mut dyn Write, data: Value) -> miette::Result<()> {
|
||||||
|
serde_xml_rs::to_writer(out, &data)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("XML serialization error")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(&self, data: &mut dyn Read) -> miette::Result<Value> {
|
||||||
|
serde_xml_rs::from_reader(data)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("XML deserialization error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_filetype_backend!(XmlBackend, ["xml", "html"]);
|
24
sercon-backends/src/backends/yaml.rs
Normal file
24
sercon-backends/src/backends/yaml.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
use miette::{Context, IntoDiagnostic};
|
||||||
|
use sercon_base::Backend;
|
||||||
|
use serde_value::Value;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct YamlBackend;
|
||||||
|
|
||||||
|
impl Backend for YamlBackend {
|
||||||
|
fn serialize(&self, out: &mut dyn Write, data: Value) -> miette::Result<()> {
|
||||||
|
serde_yaml::to_writer(out, &data)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("YAML serialization error")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(&self, data: &mut dyn Read) -> miette::Result<Value> {
|
||||||
|
serde_yaml::from_reader(data)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("YAML deserialization error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_filetype_backend!(YamlBackend, ["yml", "yaml"]);
|
24
sercon-backends/src/lib.rs
Normal file
24
sercon-backends/src/lib.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use sercon_base::Backend;
|
||||||
|
|
||||||
|
use crate::backends::*;
|
||||||
|
|
||||||
|
pub mod backends;
|
||||||
|
|
||||||
|
pub trait FiletypeBackend: Backend {
|
||||||
|
fn supported_filetypes(&self) -> Vec<String>;
|
||||||
|
fn as_backend(&self) -> &dyn Backend;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn all() -> Vec<Box<dyn FiletypeBackend>> {
|
||||||
|
vec![
|
||||||
|
Box::new(BincodeBackend),
|
||||||
|
Box::new(CborBackend),
|
||||||
|
Box::new(JsonBackend),
|
||||||
|
Box::new(NbtBackend),
|
||||||
|
Box::new(RonBackend),
|
||||||
|
Box::new(SExpressionBackend),
|
||||||
|
Box::new(TomlBackend),
|
||||||
|
Box::new(XmlBackend),
|
||||||
|
Box::new(YamlBackend),
|
||||||
|
]
|
||||||
|
}
|
11
sercon-base/Cargo.toml
Normal file
11
sercon-base/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "sercon-base"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
miette = "4.2"
|
||||||
|
serde = "1.0"
|
||||||
|
serde-value = "0.7"
|
25
sercon-base/src/lib.rs
Normal file
25
sercon-base/src/lib.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
use miette::Context;
|
||||||
|
use serde_value::Value;
|
||||||
|
|
||||||
|
pub trait Backend {
|
||||||
|
fn serialize(&self, out: &mut dyn Write, data: Value) -> miette::Result<()>;
|
||||||
|
fn deserialize(&self, data: &mut dyn Read) -> miette::Result<Value>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transcode(
|
||||||
|
inp: &mut dyn Read,
|
||||||
|
out: &mut dyn Write,
|
||||||
|
ser_backend: &dyn Backend,
|
||||||
|
de_backend: &dyn Backend,
|
||||||
|
) -> miette::Result<()> {
|
||||||
|
let data = de_backend
|
||||||
|
.deserialize(inp)
|
||||||
|
.wrap_err("error in deserialization backend")?;
|
||||||
|
ser_backend
|
||||||
|
.serialize(out, data)
|
||||||
|
.wrap_err("error in serialization backend")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
18
sercon-cli/Cargo.toml
Normal file
18
sercon-cli/Cargo.toml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
[package]
|
||||||
|
name = "sercon-cli"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "sercon"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
miette = { version = "4.2", features = ["fancy"] }
|
||||||
|
serde = "1.0"
|
||||||
|
serde-value = "0.7"
|
||||||
|
clap = { version = "3.1", features = ["derive"] }
|
||||||
|
sercon-base = { path = "../sercon-base" }
|
||||||
|
sercon-backends = { path = "../sercon-backends" }
|
129
sercon-cli/src/main.rs
Normal file
129
sercon-cli/src/main.rs
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
use std::{
|
||||||
|
fs::{File, OpenOptions},
|
||||||
|
io::{self, Read, Write},
|
||||||
|
path::PathBuf,
|
||||||
|
};
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
|
use miette::{miette, Context, IntoDiagnostic};
|
||||||
|
|
||||||
|
/// Convert between different data formats.
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Opt {
|
||||||
|
/// The input file to convert. stdin is used if omitted.
|
||||||
|
/// The type will be inferred if not explicitly specified.
|
||||||
|
#[clap(short, long)]
|
||||||
|
infile: Option<PathBuf>,
|
||||||
|
|
||||||
|
/// The output file to write the output to. stdout is used if omitted.
|
||||||
|
/// The type will be inferred if not explicitly specified.
|
||||||
|
#[clap(short, long)]
|
||||||
|
outfile: Option<PathBuf>,
|
||||||
|
|
||||||
|
/// The format used to parse the input.
|
||||||
|
#[clap(
|
||||||
|
short = 'f',
|
||||||
|
long,
|
||||||
|
required_unless_present_any = &["infile", "list-formats"],
|
||||||
|
)]
|
||||||
|
informat: Option<String>,
|
||||||
|
|
||||||
|
/// The format to convert the input into.
|
||||||
|
#[clap(
|
||||||
|
short = 't',
|
||||||
|
long,
|
||||||
|
required_unless_present_any = &["outfile", "list-formats"],
|
||||||
|
)]
|
||||||
|
outformat: Option<String>,
|
||||||
|
|
||||||
|
/// List all supported formats and exit.
|
||||||
|
#[clap(long, exclusive = true)]
|
||||||
|
list_formats: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> miette::Result<()> {
|
||||||
|
let opt = Opt::parse();
|
||||||
|
|
||||||
|
if opt.list_formats {
|
||||||
|
println!(
|
||||||
|
"{}",
|
||||||
|
sercon_backends::all()
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|b| b.supported_filetypes())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n")
|
||||||
|
);
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let informat = opt
|
||||||
|
.informat
|
||||||
|
.or_else(|| {
|
||||||
|
opt.infile
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|p| p.extension().map(|s| s.to_string_lossy().to_string()))
|
||||||
|
})
|
||||||
|
.ok_or_else(|| miette!("Couldn't infer input format. Please specify explicitly."))?;
|
||||||
|
|
||||||
|
let outformat = opt
|
||||||
|
.outformat
|
||||||
|
.or_else(|| {
|
||||||
|
opt.outfile
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|p| p.extension().map(|s| s.to_string_lossy().to_string()))
|
||||||
|
})
|
||||||
|
.ok_or_else(|| miette!("Couldn't infer output format. Please specify explicitly."))?;
|
||||||
|
|
||||||
|
let backends = sercon_backends::all();
|
||||||
|
|
||||||
|
let in_backend = backends
|
||||||
|
.iter()
|
||||||
|
.find(|b| b.supported_filetypes().contains(&informat))
|
||||||
|
.ok_or_else(|| miette!("No parser found for input format '{}'!", &informat))?;
|
||||||
|
|
||||||
|
let out_backend = backends
|
||||||
|
.iter()
|
||||||
|
.find(|b| b.supported_filetypes().contains(&outformat))
|
||||||
|
.ok_or_else(|| miette!("No parser found for output format '{}'!", &outformat))?;
|
||||||
|
|
||||||
|
let mut input: Box<dyn Read> = if let Some(p) = opt.infile {
|
||||||
|
Box::new(
|
||||||
|
File::open(p)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("Failed to open infile")?,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Box::new(io::stdin())
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut using_stdout = false;
|
||||||
|
let mut output: Box<dyn Write> = if let Some(p) = opt.outfile {
|
||||||
|
Box::new(
|
||||||
|
OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.open(p)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("Failed to open outfile")?,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
using_stdout = true;
|
||||||
|
Box::new(io::stdout())
|
||||||
|
};
|
||||||
|
|
||||||
|
sercon_base::transcode(
|
||||||
|
&mut input,
|
||||||
|
&mut output,
|
||||||
|
out_backend.as_backend(),
|
||||||
|
in_backend.as_backend(),
|
||||||
|
)
|
||||||
|
.wrap_err("error during transcoding")?;
|
||||||
|
|
||||||
|
if using_stdout {
|
||||||
|
println!();
|
||||||
|
io::stdout().flush().into_diagnostic()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in a new issue