//! Reading and parsing the arguments `brokerd` puts on `toolkit`'s standard input. use std::io::Read; pub const MAX_INPUT: usize = 2 * 1024 * 1024; #[derive(Debug)] pub enum InputError { TooLarge, NotUtf8, Io(std::io::Error), } impl std::fmt::Display for InputError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { InputError::TooLarge => write!(f, "the arguments are larger than {MAX_INPUT} bytes"), InputError::NotUtf8 => write!(f, "the arguments are not UTF-8"), InputError::Io(e) => write!(f, "cannot read the arguments: {e}"), } } } impl std::error::Error for InputError {} impl From for InputError { fn from(e: std::io::Error) -> Self { InputError::Io(e) } } /// All of `stdin`, at most MAX_INPUT bytes, as UTF-8. Read at most MAX_INPUT + 1 bytes /// (`Read::take`); more than MAX_INPUT is TooLarge. pub fn read_input(stdin: &mut dyn std::io::Read) -> Result { let mut buf = Vec::new(); let n = stdin .take(u64::try_from(MAX_INPUT).map_or(u64::MAX, |n| n.saturating_add(1))) .read_to_end(&mut buf)?; if n > MAX_INPUT { return Err(InputError::TooLarge); } String::from_utf8(buf).map_err(|_| InputError::NotUtf8) } /// Parse `text` as the arguments of tool `name`; the error is the whole line for stderr: /// "toolkit: {name}: the arguments do not parse: {serde's error}". pub fn parse(name: &str, text: &str) -> Result { serde_json::from_str(text) .map_err(|e| format!("toolkit: {name}: the arguments do not parse: {e}")) }