Skip to main content

weavatrix_edit/application/
stream.rs

1use std::iter::FusedIterator;
2
3use super::PreparedEdit;
4
5/// Zero-copy chunks of one already-validated edit result.
6///
7/// Chunks borrow either the immutable source or prepared replacement text.
8/// Empty source spans and empty replacements are skipped.
9#[derive(Clone, Debug)]
10pub struct EditChunks<'prepared> {
11    source: &'prepared str,
12    edits: &'prepared [PreparedEdit],
13    edit_index: usize,
14    cursor: usize,
15    finished: bool,
16}
17
18impl<'prepared> EditChunks<'prepared> {
19    pub(super) const fn new(source: &'prepared str, edits: &'prepared [PreparedEdit]) -> Self {
20        Self {
21            source,
22            edits,
23            edit_index: 0,
24            cursor: 0,
25            finished: false,
26        }
27    }
28}
29
30impl<'prepared> Iterator for EditChunks<'prepared> {
31    type Item = &'prepared str;
32
33    fn next(&mut self) -> Option<Self::Item> {
34        loop {
35            if let Some(edit) = self.edits.get(self.edit_index) {
36                if self.cursor < edit.start {
37                    let unchanged = &self.source[self.cursor..edit.start];
38                    self.cursor = edit.start;
39                    return Some(unchanged);
40                }
41                self.edit_index += 1;
42                self.cursor = self.cursor.max(edit.end);
43                if !edit.after.is_empty() {
44                    return Some(&edit.after);
45                }
46                continue;
47            }
48            if self.finished {
49                return None;
50            }
51            self.finished = true;
52            if self.cursor < self.source.len() {
53                return Some(&self.source[self.cursor..]);
54            }
55        }
56    }
57
58    fn size_hint(&self) -> (usize, Option<usize>) {
59        let edits_left = self.edits.len().saturating_sub(self.edit_index);
60        (
61            0,
62            edits_left
63                .checked_mul(2)
64                .and_then(|size| size.checked_add(1)),
65        )
66    }
67}
68
69impl FusedIterator for EditChunks<'_> {}