// Copyright © 2022 Kim Altintop // SPDX-License-Identifier: GPL-2.0-only WITH openvpn-openssl-exception use sha2::{ digest::generic_array::GenericArray, Digest, }; /// Created by [`Lines::until_blank`], stops iteration at the first blank line. pub struct UntilBlank { inner: Lines, } impl Iterator for UntilBlank { type Item = std::io::Result; fn next(&mut self) -> Option { self.inner.next().and_then(|res| match res { Ok(line) => { if line.is_empty() { None } else { Some(Ok(line)) } }, Err(e) => Some(Err(e)), }) } } impl std::io::Seek for UntilBlank { fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result { self.inner.seek(pos) } } /// Like [`std::io::Lines`], but allows to retain ownership of the underlying /// [`std::io::BufRead`]. pub struct Lines { buf: B, } impl Lines { pub fn new(buf: B) -> Self { Self { buf } } pub fn until_blank(self) -> UntilBlank { UntilBlank { inner: self } } } impl Iterator for Lines { type Item = std::io::Result; fn next(&mut self) -> Option { let mut buf = String::new(); match self.buf.read_line(&mut buf) { Ok(0) => None, Ok(_) => { if buf.ends_with('\n') { buf.pop(); if buf.ends_with('\r') { buf.pop(); } } Some(Ok(buf)) }, Err(e) => Some(Err(e)), } } } impl std::io::Seek for Lines { fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result { self.buf.seek(pos) } } /// A [`std::io::Write`] which also computes a hash digest from the bytes /// written to it. pub struct HashWriter { hasher: D, writer: W, } impl HashWriter { pub fn new(hasher: D, writer: W) -> Self { Self { hasher, writer } } } impl HashWriter where D: Digest, { pub fn hash(self) -> GenericArray { self.hasher.finalize() } } impl std::io::Write for HashWriter where D: Digest, W: std::io::Write, { fn write(&mut self, buf: &[u8]) -> std::io::Result { self.hasher.update(buf); self.writer.write(buf) } fn flush(&mut self) -> std::io::Result<()> { self.writer.flush() } } /// A [`std::io::Write`] which keeps track of the number of bytes written to it pub struct LenWriter { written: u64, writer: W, } impl LenWriter { pub fn new(writer: W) -> Self { Self { written: 0, writer } } pub fn bytes_written(&self) -> u64 { self.written } } impl std::io::Write for LenWriter where W: std::io::Write, { fn write(&mut self, buf: &[u8]) -> std::io::Result { let n = self.writer.write(buf)?; self.written += n as u64; Ok(n) } fn flush(&mut self) -> std::io::Result<()> { self.writer.flush() } }