tiny_str/drain.rs
1//! [drain](TinyString::drain) implementation
2
3use core::iter::FusedIterator;
4use core::marker::PhantomData;
5use core::mem::ManuallyDrop;
6use core::ops::{Range, RangeBounds};
7use core::ptr::{self, NonNull};
8use core::{slice, str};
9use crate::TinyString;
10
11/// A draining iterator for [TinyString]
12///
13/// This struct is created by the [TinyString::drain] method
14pub struct Drain<'a, const N: usize> {
15 string: NonNull<TinyString<N>>,
16 remaining_start: usize,
17 remaining_len: usize,
18 tail_start: usize,
19 tail_len: usize,
20 _marker: PhantomData<&'a mut TinyString<N>>,
21}
22
23impl<const N: usize> Drain<'_, N> {
24
25 /// Returns the remaining slice
26 pub const fn as_str(&mut self) -> &str {
27 if self.remaining_len == 0 {
28 return ""
29 }
30 unsafe {
31 let str = self.string.as_ref().as_ptr().add(self.remaining_start);
32 let slice = slice::from_raw_parts(str, self.remaining_len);
33 str::from_utf8_unchecked(slice)
34 }
35 }
36
37 /// Consumes this [Drain], preserving any un-yielded characters
38 ///
39 /// # Example
40 /// ```
41 /// use tiny_str::TinyString;
42 ///
43 /// let mut tv = TinyString::<10>::from("abcdefghijk");
44 ///
45 /// let mut drain = tv.drain(3..7);
46 ///
47 /// assert_eq!(drain.next(), Some('d'));
48 /// assert_eq!(drain.next(), Some('e'));
49 ///
50 /// drain.keep_rest();
51 ///
52 /// assert_eq!(tv.as_str(), "abcfghijk");
53 /// ```
54 pub fn keep_rest(self) {
55 let mut slf = ManuallyDrop::new(self);
56
57 /* [ HEAD ] [ yieled | remaining | yielded_back ] [ TAIL ] */
58 unsafe {
59 let string = slf.string.as_mut();
60 let start = string.len();
61
62 let buf = string.as_mut_ptr();
63
64 let dst = buf.add(start);
65 let src = buf.add(slf.remaining_start);
66 /* First: We move the remaining chunk to the start */
67 ptr::copy(src, dst, slf.remaining_len);
68
69 let src = buf.add(slf.tail_start);
70 let dst = dst.add(slf.remaining_len);
71 /* Now we move the tail */
72 ptr::copy(src, dst, slf.tail_len);
73
74 string.buf.set_len(start + slf.remaining_len + slf.tail_len);
75 }
76 }
77}
78
79impl<const N: usize> Iterator for Drain<'_, N> {
80 type Item = char;
81
82 fn next(&mut self) -> Option<Self::Item> {
83 let c = self.as_str().chars().next()?;
84 self.remaining_start += c.len_utf8();
85 self.remaining_len -= c.len_utf8();
86 Some(c)
87 }
88
89 fn size_hint(&self) -> (usize, Option<usize>) {
90 (self.remaining_len, Some(self.remaining_len))
91 }
92}
93
94impl<const N: usize> DoubleEndedIterator for Drain<'_, N> {
95 fn next_back(&mut self) -> Option<Self::Item> {
96 let c = self.as_str().chars().next_back()?;
97 self.remaining_len -= c.len_utf8();
98 Some(c)
99 }
100}
101
102impl<const N: usize> ExactSizeIterator for Drain<'_, N> {}
103
104impl<const N: usize> FusedIterator for Drain<'_, N> {}
105
106impl<const N: usize> Drop for Drain<'_, N> {
107 fn drop(&mut self) {
108 unsafe {
109 let string = self.string.as_mut();
110 let len = string.len();
111 let ptr = string.as_mut_ptr();
112
113 let src = ptr.add(self.tail_start);
114 let dst = ptr.add(len);
115 ptr::copy(src, dst, self.tail_len);
116
117 string.buf.set_len(len + self.tail_len);
118 }
119 }
120}
121
122impl<const N: usize> TinyString<N> {
123
124 /// Removes the substring indicated by the given range from the string,
125 /// returning a double-ended iterator over the removed substring.
126 ///
127 /// If the iterator is dropped before being fully consumed,
128 /// it drops the remaining removed elements.
129 ///
130 /// # Panics
131 ///
132 /// Panics if the starting point is greater than the end point, if
133 /// the end point is greater than the length of the vector,
134 /// or if any of the ends of the range fall outside a char boundary.
135 ///
136 /// # Leaking
137 ///
138 /// If the returned iterator goes out of scope without being dropped (due to
139 /// [`core::mem::forget`], for example), the vector may have lost characters
140 /// arbitrarily, including characters outside the range.
141 ///
142 /// # Examples
143 ///
144 /// ```
145 /// use tiny_str::TinyString;
146 /// let mut s = TinyString::<10>::from("abcdefghijk");
147 ///
148 /// let mut drain = s.drain(2..=4);
149 /// assert_eq!(drain.next(), Some('c'));
150 /// assert_eq!(drain.next(), Some('d'));
151 /// assert_eq!(drain.next(), Some('e'));
152 /// assert_eq!(drain.next(), None);
153 /// drop(drain);
154 ///
155 /// assert_eq!(s.as_str(), "abfghijk");
156 ///
157 /// // A full range clears the string, like `clear()` does
158 /// s.drain(..);
159 /// assert_eq!(s.as_str(), "");
160 /// ```
161 pub fn drain<R>(&mut self, range: R) -> Drain<'_, N>
162 where
163 R: RangeBounds<usize>
164 {
165 let len = self.len();
166 let Range { start, end } = self.slice_range(range, len);
167 unsafe {
168 self.buf.set_len(start);
169
170 let string = NonNull::new_unchecked(self as *mut _);
171 Drain {
172 tail_len: len - end,
173 tail_start: end,
174 remaining_start: start,
175 remaining_len: end - start,
176 string,
177 _marker: PhantomData,
178 }
179 }
180 }
181}