/* This file is part of jellything (https://codeberg.org/metamuffin/jellything) which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2025 metamuffin */ use anyhow::anyhow; use log::{trace, warn}; use std::{ io::{Seek, Write}, ops::Range, }; 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 tbuf = &buf[start..end]; Ok(if !tbuf.is_empty() { trace!("trim={start}..{end} avail={}", buf.len()); let sz = self.inner.write(tbuf)?; self.position += sz; sz } else { trace!("skip={}", buf.len()); 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: pos={} end={}", self.position, self.range.end ) } Ok(self.position as u64) } }