use crate::commands::{ClapArgs, CommandExecutor, ConfigurableCommand}; use crate::config::AppConfig; use crate::config::System; use crate::container::Container; use anyhow::{Context, Result}; use async_trait::async_trait; use config::ConfigBuilder; use config::builder::DefaultState; use serde::Deserialize; #[derive(Debug, Deserialize, Clone)] pub struct Config { pub system: System, pub input: String, } #[derive(ClapArgs, Debug, Clone)] pub struct DecodeArgs { #[arg(short, long, help = defaults::HELP_DEC_SYSTEM)] pub system: Option, #[arg(short, long, help = defaults::HELP_DEC_INPUT)] pub input: String, } impl ConfigurableCommand for DecodeArgs { fn apply_defaults( &self, builder: ConfigBuilder, ) -> Result> { builder .set_default("decode.system", defaults::DEC_SYSTEM_NAME)? .set_default("decode.input", "") .map_err(Into::into) } fn apply_overrides( &self, builder: ConfigBuilder, ) -> Result> { let mut builder = builder; if let Some(ref system) = self.system { builder = builder.set_override("decode.system", system.clone())?; } builder = builder.set_override("decode.input", self.input.clone())?; Ok(builder) } } #[async_trait] impl CommandExecutor for DecodeArgs { async fn execute(&self, config: &AppConfig, container: &Container) -> Result<()> { let config = config .decode .as_ref() .ok_or_else(|| anyhow::anyhow!("Decoder config missing"))?; let decoder = container.create_decoder(&config)?; let result = decoder .decode(&config.input) .with_context(|| format!("Failed to decode input: {}", config.input))?; let json = serde_json::to_string_pretty(&result).expect("JSON serialization failed"); println!("{}", json); Ok(()) } } mod defaults { use const_format::formatcp; pub const DEC_SYSTEM_NAME: &str = "major_pl"; pub const HELP_DEC_SYSTEM: &str = formatcp!("System to use [default: {}]", DEC_SYSTEM_NAME); pub const HELP_DEC_INPUT: &str = formatcp!("Text to decode"); }