rope_rd/
sparse.rs

1//! Utilities for interspersing real data with filler bytes.
2//!
3//! The [`Spacer`] represents these filler bytes.
4//! The [`Part`] represents something which can either be real data or a [`Spacer`].
5use std::fmt::Debug;
6use std::io;
7use std::io::{Read, Seek, SeekFrom};
8
9use crate::util::abs_position;
10use crate::Node;
11
12/// [`Read`]able, [`Seek`]able [`Iterator`] with a given length and fill value.
13///
14/// Implements [`Into`] for [`Node`](crate::Node)s.
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub struct Spacer {
17    length: u64,
18    fill: u8,
19    position: u64,
20}
21
22impl Iterator for Spacer {
23    type Item = u8;
24
25    fn next(&mut self) -> Option<Self::Item> {
26        if self.position >= self.length {
27            None
28        } else {
29            self.position += 1;
30            Some(self.fill)
31        }
32    }
33
34    fn size_hint(&self) -> (usize, Option<usize>) {
35        let rem = self.remaining() as usize;
36        (rem, Some(rem))
37    }
38}
39
40impl Spacer {
41    /// Create a new spacer with the given length, and default fill value.
42    pub fn new(length: u64) -> Self {
43        Self::with_fill(length, Default::default())
44    }
45
46    /// Create a new spacer with the given length and fill value.
47    pub fn with_fill(length: u64, fill: u8) -> Self {
48        Self {
49            length,
50            fill,
51            position: 0,
52        }
53    }
54
55    /// Number of bytes remaining in the spacer.
56    ///
57    /// The position can be changed by iteration, reading, or seeking.
58    pub fn remaining(&self) -> u64 {
59        self.length - self.position.min(self.length)
60    }
61}
62
63impl Read for Spacer {
64    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
65        let mut idx = 0;
66        for (el, val) in buf.iter_mut().zip(self) {
67            *el = val;
68            idx += 1;
69        }
70        Ok(idx)
71    }
72}
73
74impl Seek for Spacer {
75    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
76        self.position = abs_position(self.position, self.length, pos)?;
77        Ok(self.position)
78    }
79}
80
81/// Enum representing part of a readable which may be full or empty.
82///
83/// If empty, it is filled by a [`Spacer`];
84/// if full, by some other [`Read`] & [`Seek`]able.
85///
86/// Implements [`TryInto`] for [`Node`](crate::Node)s.
87pub enum Part<F: Read + Seek> {
88    Full(F),
89    Empty(Spacer),
90}
91
92impl<F: Read + Seek + Debug> Debug for Part<F> {
93    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94        match self {
95            Self::Full(arg0) => f.debug_tuple("Full").field(arg0).finish(),
96            Self::Empty(arg0) => f.debug_tuple("Empty").field(arg0).finish(),
97        }
98    }
99}
100
101impl<F: Read + Seek> Part<F> {
102    /// Create an empty part with the given length and the default fill.
103    pub fn empty(length: u64) -> Self {
104        Spacer::new(length).into()
105    }
106
107    /// Create an empty part with the given length and fill.
108    pub fn empty_with_fill(length: u64, fill: u8) -> Self {
109        Spacer::with_fill(length, fill).into()
110    }
111}
112
113impl<F: Read + Seek> Read for Part<F> {
114    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
115        match self {
116            Part::Full(r) => r.read(buf),
117            Part::Empty(r) => r.read(buf),
118        }
119    }
120}
121
122impl<F: Read + Seek> Seek for Part<F> {
123    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
124        match self {
125            Part::Full(s) => s.seek(pos),
126            Part::Empty(s) => s.seek(pos),
127        }
128    }
129}
130
131impl<F: Read + Seek> From<Spacer> for Part<F> {
132    fn from(val: Spacer) -> Self {
133        Part::Empty(val)
134    }
135}
136
137impl<F: Read + Seek> TryInto<Node<Part<F>>> for Part<F> {
138    fn try_into(self) -> Result<Node<Part<F>>, Self::Error> {
139        Node::leaf(self)
140    }
141
142    type Error = io::Error;
143}
144
145impl<F: Read + Seek> From<Spacer> for Node<Part<F>> {
146    fn from(val: Spacer) -> Self {
147        let len = val.length;
148        Node::leaf_with_length(val.into(), len)
149    }
150}
151
152#[cfg(test)]
153mod tests {
154    use super::*;
155
156    #[test]
157    fn iter() {
158        let len = 100;
159        let s = Spacer::new(len);
160        let v: Vec<_> = s.collect();
161        assert_eq!(v, vec![0; len as usize])
162    }
163
164    #[test]
165    fn read() {
166        let len = 100;
167        let mut s = Spacer::new(len);
168        let mut v = Vec::default();
169        s.read_to_end(&mut v).unwrap();
170        assert_eq!(v, vec![0; len as usize])
171    }
172
173    #[test]
174    fn seek() {
175        let len = 100;
176        let mut s = Spacer::new(len);
177        let mut v = Vec::default();
178        s.seek(SeekFrom::Start(50)).unwrap();
179        s.read_to_end(&mut v).unwrap();
180        assert_eq!(v, vec![0; len as usize - 50])
181    }
182}