use std::{ io::{Seek, Write}, ops::Range, }; use anyhow::anyhow; use log::warn; pub struct TrimWriter { inner: W, position: usize, range: Range, } impl TrimWriter { pub fn new(inner: W, range: Range) -> Self { Self { inner, range, position: 0, } } } impl Write for TrimWriter { fn write(&mut self, buf: &[u8]) -> std::io::Result { let start = self.range.start as isize - self.position as isize; let end = self.range.end as isize - self.position as isize; let start = start.clamp(0, buf.len() as isize) as usize; let end = end.clamp(0, buf.len() as isize) as usize; if self.position >= self.range.end { return Err(std::io::Error::new( std::io::ErrorKind::Other, anyhow!("range ended"), )); } let buf = &buf[start..end]; if !buf.is_empty() { self.inner.write_all(buf)?; self.position += buf.len() } Ok(buf.len()) } fn flush(&mut self) -> std::io::Result<()> { self.inner.flush() } } impl Seek for TrimWriter { fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result { match pos { std::io::SeekFrom::Start(s) => self.position = s as usize, std::io::SeekFrom::End(_) => unimplemented!(), std::io::SeekFrom::Current(s) => self.position += s as usize, } if self.position < self.range.end { warn!("seeked beyond end") } Ok(self.position as u64) } }