Skip to content

Commit 464f771

Browse files
committed
100% safe implementation of RepeatN
1 parent f2becdf commit 464f771

File tree

1 file changed

+42
-86
lines changed

1 file changed

+42
-86
lines changed
+42-86
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::fmt;
22
use crate::iter::{FusedIterator, TrustedLen, UncheckedIterator};
3-
use crate::mem::{self, MaybeUninit};
43
use crate::num::NonZero;
54

65
/// Creates a new iterator that repeats a single element a given number of times.
@@ -59,78 +58,48 @@ use crate::num::NonZero;
5958
#[inline]
6059
#[stable(feature = "iter_repeat_n", since = "1.82.0")]
6160
pub fn repeat_n<T: Clone>(element: T, count: usize) -> RepeatN<T> {
62-
let element = if count == 0 {
63-
// `element` gets dropped eagerly.
64-
MaybeUninit::uninit()
65-
} else {
66-
MaybeUninit::new(element)
67-
};
68-
69-
RepeatN { element, count }
61+
RepeatN { inner: RepeatNInner::new(element, count) }
62+
}
63+
64+
#[derive(Clone)]
65+
struct RepeatNInner<T> {
66+
element: T,
67+
count: NonZero<usize>,
68+
}
69+
70+
impl<T> RepeatNInner<T> {
71+
fn new(element: T, count: usize) -> Option<Self> {
72+
let count = NonZero::<usize>::new(count)?;
73+
Some(Self { element, count })
74+
}
7075
}
7176

7277
/// An iterator that repeats an element an exact number of times.
7378
///
7479
/// This `struct` is created by the [`repeat_n()`] function.
7580
/// See its documentation for more.
7681
#[stable(feature = "iter_repeat_n", since = "1.82.0")]
82+
#[derive(Clone)]
7783
pub struct RepeatN<A> {
78-
count: usize,
79-
// Invariant: uninit iff count == 0.
80-
element: MaybeUninit<A>,
84+
inner: Option<RepeatNInner<A>>,
8185
}
8286

8387
impl<A> RepeatN<A> {
84-
/// Returns the element if it hasn't been dropped already.
85-
fn element_ref(&self) -> Option<&A> {
86-
if self.count > 0 {
87-
// SAFETY: The count is non-zero, so it must be initialized.
88-
Some(unsafe { self.element.assume_init_ref() })
89-
} else {
90-
None
91-
}
92-
}
9388
/// If we haven't already dropped the element, return it in an option.
94-
///
95-
/// Clears the count so it won't be dropped again later.
9689
#[inline]
9790
fn take_element(&mut self) -> Option<A> {
98-
if self.count > 0 {
99-
self.count = 0;
100-
let element = mem::replace(&mut self.element, MaybeUninit::uninit());
101-
// SAFETY: We just set count to zero so it won't be dropped again,
102-
// and it used to be non-zero so it hasn't already been dropped.
103-
unsafe { Some(element.assume_init()) }
104-
} else {
105-
None
106-
}
107-
}
108-
}
109-
110-
#[stable(feature = "iter_repeat_n", since = "1.82.0")]
111-
impl<A: Clone> Clone for RepeatN<A> {
112-
fn clone(&self) -> RepeatN<A> {
113-
RepeatN {
114-
count: self.count,
115-
element: self.element_ref().cloned().map_or_else(MaybeUninit::uninit, MaybeUninit::new),
116-
}
91+
self.inner.take().map(|inner| inner.element)
11792
}
11893
}
11994

12095
#[stable(feature = "iter_repeat_n", since = "1.82.0")]
12196
impl<A: fmt::Debug> fmt::Debug for RepeatN<A> {
12297
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123-
f.debug_struct("RepeatN")
124-
.field("count", &self.count)
125-
.field("element", &self.element_ref())
126-
.finish()
127-
}
128-
}
129-
130-
#[stable(feature = "iter_repeat_n", since = "1.82.0")]
131-
impl<A> Drop for RepeatN<A> {
132-
fn drop(&mut self) {
133-
self.take_element();
98+
let (count, element) = match self.inner.as_ref() {
99+
Some(inner) => (inner.count.get(), Some(&inner.element)),
100+
None => (0, None),
101+
};
102+
f.debug_struct("RepeatN").field("count", &count).field("element", &element).finish()
134103
}
135104
}
136105

@@ -140,12 +109,15 @@ impl<A: Clone> Iterator for RepeatN<A> {
140109

141110
#[inline]
142111
fn next(&mut self) -> Option<A> {
143-
if self.count > 0 {
144-
// SAFETY: Just checked it's not empty
145-
unsafe { Some(self.next_unchecked()) }
146-
} else {
147-
None
112+
let inner = self.inner.as_mut()?;
113+
let count = inner.count.get();
114+
115+
if let Some(decremented) = NonZero::<usize>::new(count - 1) {
116+
inner.count = decremented;
117+
return Some(inner.element.clone());
148118
}
119+
120+
return self.take_element();
149121
}
150122

151123
#[inline]
@@ -156,19 +128,19 @@ impl<A: Clone> Iterator for RepeatN<A> {
156128

157129
#[inline]
158130
fn advance_by(&mut self, skip: usize) -> Result<(), NonZero<usize>> {
159-
let len = self.count;
131+
let Some(inner) = self.inner.as_mut() else {
132+
return NonZero::<usize>::new(skip).map(Err).unwrap_or(Ok(()));
133+
};
160134

161-
if skip >= len {
162-
self.take_element();
163-
}
135+
let len = inner.count.get();
164136

165-
if skip > len {
166-
// SAFETY: we just checked that the difference is positive
167-
Err(unsafe { NonZero::new_unchecked(skip - len) })
168-
} else {
169-
self.count = len - skip;
170-
Ok(())
137+
if let Some(new_len) = len.checked_sub(skip).and_then(NonZero::<usize>::new) {
138+
inner.count = new_len;
139+
return Ok(());
171140
}
141+
142+
self.inner = None;
143+
return NonZero::<usize>::new(skip - len).map(Err).unwrap_or(Ok(()));
172144
}
173145

174146
#[inline]
@@ -185,7 +157,7 @@ impl<A: Clone> Iterator for RepeatN<A> {
185157
#[stable(feature = "iter_repeat_n", since = "1.82.0")]
186158
impl<A: Clone> ExactSizeIterator for RepeatN<A> {
187159
fn len(&self) -> usize {
188-
self.count
160+
self.inner.as_ref().map(|inner| inner.count.get()).unwrap_or(0)
189161
}
190162
}
191163

@@ -213,20 +185,4 @@ impl<A: Clone> FusedIterator for RepeatN<A> {}
213185
#[unstable(feature = "trusted_len", issue = "37572")]
214186
unsafe impl<A: Clone> TrustedLen for RepeatN<A> {}
215187
#[stable(feature = "iter_repeat_n", since = "1.82.0")]
216-
impl<A: Clone> UncheckedIterator for RepeatN<A> {
217-
#[inline]
218-
unsafe fn next_unchecked(&mut self) -> Self::Item {
219-
// SAFETY: The caller promised the iterator isn't empty
220-
self.count = unsafe { self.count.unchecked_sub(1) };
221-
if self.count == 0 {
222-
// SAFETY: the check above ensured that the count used to be non-zero,
223-
// so element hasn't been dropped yet, and we just lowered the count to
224-
// zero so it won't be dropped later, and thus it's okay to take it here.
225-
unsafe { mem::replace(&mut self.element, MaybeUninit::uninit()).assume_init() }
226-
} else {
227-
// SAFETY: the count is non-zero, so it must have not been dropped yet.
228-
let element = unsafe { self.element.assume_init_ref() };
229-
A::clone(element)
230-
}
231-
}
232-
}
188+
impl<A: Clone> UncheckedIterator for RepeatN<A> {}

0 commit comments

Comments
 (0)