use std::{ env, io::{ self, Read, Write, }, }; use anyhow::{ Result, bail, }; use sha2::Digest; fn main () -> Result <()> { let mut opts = parse_opts (env::args ())?; let mut stdin = io::stdin ().lock (); let mut stdout = io::stdout ().lock (); let buffer_size = 512 * 1_024; loop { let mut buf = vec! [0u8; buffer_size]; let bytes_read = stdin.read (&mut buf)?; if bytes_read == 0 { break; } let buf = &buf [0..bytes_read]; if let Some ((h, _)) = opts.sha384.as_mut () { h.update (buf); } if let Some ((h, _)) = opts.blake3.as_mut () { h.update (buf); } stdout.write_all (&buf)?; } if let Some ((h, expected)) = opts.sha384 { let actual = hex::encode (h.finalize ()); if expected != actual { bail! ("SHA384 doesn't match. Expected {}, actual {}", expected, actual); } } if let Some ((h, expected)) = opts.blake3 { let actual = h.finalize (); if expected != actual { bail! ("BLAKE3 doesn't match. Expected {:?}, actual {:?}", expected, actual); } } Ok (()) } #[derive (Default)] struct Opts { blake3: Option <(blake3::Hasher, blake3::Hash)>, sha384: Option <(sha2::Sha384, String)>, } fn parse_opts > (mut args: I) -> Result { let mut opts = Opts::default (); loop { let arg = match args.next () { None => return Ok (opts), Some (x) => x, }; if arg == "--blake3" { match args.next () { None => bail! ("Missing argument for --blake3"), Some (x) => opts.blake3 = Some ((blake3::Hasher::new (), blake3::Hash::from_hex (x)?)), } } else if arg == "--sha384" { match args.next () { None => bail! ("Missing argument for --sha384"), Some (x) => opts.sha384 = Some ((sha2::Sha384::new (), x)), } } } }