1use core::{fmt, iter::FusedIterator};
2
3use crate::utf8_edit::{RawUtf8Storage, scalar_width};
4
5pub struct Utf8Drain<'a> {
22 storage: RawUtf8Storage<'a>,
23 start: usize,
24 end: usize,
25 original_len: usize,
26 front: usize,
27 back: usize,
28}
29
30impl<'a> Utf8Drain<'a> {
31 pub(crate) fn new(storage: RawUtf8Storage<'a>, start: usize, end: usize) -> Self {
32 let original_len = storage.len();
33 Self {
34 storage,
35 start,
36 end,
37 original_len,
38 front: start,
39 back: end,
40 }
41 }
42
43 pub fn as_str(&self) -> &str {
45 core::str::from_utf8(&self.storage.as_slice()[self.front..self.back])
46 .expect("UTF-8 invariant violated")
47 }
48}
49
50impl fmt::Debug for Utf8Drain<'_> {
51 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
52 formatter
53 .debug_tuple("Utf8Drain")
54 .field(&self.as_str())
55 .finish()
56 }
57}
58
59impl AsRef<str> for Utf8Drain<'_> {
60 fn as_ref(&self) -> &str {
61 self.as_str()
62 }
63}
64
65impl AsRef<[u8]> for Utf8Drain<'_> {
66 fn as_ref(&self) -> &[u8] {
67 self.as_str().as_bytes()
68 }
69}
70
71impl Iterator for Utf8Drain<'_> {
72 type Item = char;
73
74 fn next(&mut self) -> Option<Self::Item> {
75 if self.front == self.back {
76 return None;
77 }
78
79 let next = {
80 let bytes = self.storage.as_slice();
81 self.front + scalar_width(bytes[self.front])
82 };
83 let character = {
84 let bytes = self.storage.as_slice();
85 core::str::from_utf8(&bytes[self.front..next])
86 .expect("UTF-8 invariant violated")
87 .chars()
88 .next()
89 .expect("UTF-8 invariant violated")
90 };
91 self.front = next;
92 Some(character)
93 }
94
95 fn size_hint(&self) -> (usize, Option<usize>) {
96 let bytes = self.back - self.front;
97 let minimum = bytes / 4 + usize::from(!bytes.is_multiple_of(4));
98 (minimum, Some(bytes))
99 }
100}
101
102impl DoubleEndedIterator for Utf8Drain<'_> {
103 fn next_back(&mut self) -> Option<Self::Item> {
104 if self.front == self.back {
105 return None;
106 }
107
108 let start = {
109 let bytes = self.storage.as_slice();
110 let mut start = self.back - 1;
111 for _ in 0..3 {
112 if start == self.front || bytes[start] & 0b1100_0000 != 0b1000_0000 {
113 break;
114 }
115 start -= 1;
116 }
117 start
118 };
119 let character = {
120 let bytes = self.storage.as_slice();
121 core::str::from_utf8(&bytes[start..self.back])
122 .expect("UTF-8 invariant violated")
123 .chars()
124 .next()
125 .expect("UTF-8 invariant violated")
126 };
127 self.back = start;
128 Some(character)
129 }
130}
131
132impl FusedIterator for Utf8Drain<'_> {}
133
134impl Drop for Utf8Drain<'_> {
135 fn drop(&mut self) {
136 self
137 .storage
138 .copy_within(self.end..self.original_len, self.start);
139 self
140 .storage
141 .truncate(self.original_len - (self.end - self.start));
142 }
143}