From d2f423521ec76406944ad83098ec33afe20c692b Mon Sep 17 00:00:00 2001 From: Kim Altintop Date: Mon, 9 Jan 2023 13:18:33 +0100 Subject: This is it Squashed commit of all the exploration history. Development starts here. Signed-off-by: Kim Altintop --- src/io.rs | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 src/io.rs (limited to 'src/io.rs') diff --git a/src/io.rs b/src/io.rs new file mode 100644 index 0000000..86f91c6 --- /dev/null +++ b/src/io.rs @@ -0,0 +1,146 @@ +// 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() + } +} -- cgit v1.2.3