use anyhow::Result;
use clap::Parser;
use clio::Output;
use hugr::envelope::{EnvelopeConfig, EnvelopeFormat, ZstdConfig};
use std::io::{Read, Write};
use crate::CliError;
use crate::hugr_io::HugrInputArgs;
#[derive(Parser, Debug)]
#[clap(version = "1.0", long_about = None)]
#[clap(about = "Convert a HUGR between different envelope formats.")]
#[group(id = "hugr")]
#[non_exhaustive]
pub struct ConvertArgs {
#[command(flatten)]
pub input_args: HugrInputArgs,
#[clap(short, long, value_parser, default_value = "-")]
pub output: Output,
#[clap(short, long, value_name = "FORMAT")]
pub format: Option<String>,
#[clap(long, conflicts_with_all = ["format", "binary"])]
pub text: bool,
#[clap(long, conflicts_with_all = ["format", "text"])]
pub binary: bool,
#[clap(long)]
pub compress: bool,
#[clap(long, value_name = "LEVEL", requires = "compress")]
pub compression_level: Option<u8>,
}
impl ConvertArgs {
pub fn run_convert_with_io<R: Read, W: Write>(
&mut self,
input_override: Option<R>,
mut output_override: Option<W>,
) -> Result<()> {
let (env_config, package) = self
.input_args
.get_described_package_with_reader(input_override)?;
let mut config = if self.text {
EnvelopeConfig::text()
} else if self.binary {
EnvelopeConfig::binary()
} else {
let format = match &self.format {
Some(fmt) => match fmt.as_str() {
#[expect(deprecated)]
"json" => EnvelopeFormat::PackageJson,
"model" => EnvelopeFormat::Model,
"model-exts" => EnvelopeFormat::ModelWithExtensions,
"model-text" | "s-expression" => EnvelopeFormat::SExpression,
"model-text-exts" | "s-expression-exts" => {
EnvelopeFormat::SExpressionWithExtensions
}
_ => Err(CliError::InvalidFormat(fmt.clone()))?,
},
None => env_config.header.config().format, };
EnvelopeConfig::new(format)
};
if let Some(level) = self.compress.then_some(self.compression_level).flatten() {
config = config.with_zstd(ZstdConfig::new(level));
}
if let Some(ref mut writer) = output_override {
hugr::envelope::write_envelope(writer, &package, config)?;
} else {
hugr::envelope::write_envelope(&mut self.output, &package, config)?;
}
Ok(())
}
pub fn run_convert(&mut self) -> Result<()> {
self.run_convert_with_io(None::<&[u8]>, None::<Vec<u8>>)
}
}