Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 5ac6709

Browse files
committed
refactor: moving SourceIterMarker into source_iter_marker.rs
1 parent 840c4e2 commit 5ac6709

File tree

2 files changed

+113
-104
lines changed

2 files changed

+113
-104
lines changed

library/alloc/src/vec/mod.rs

Lines changed: 3 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ use core::fmt;
6060
use core::hash::{Hash, Hasher};
6161
use core::intrinsics::{arith_offset, assume};
6262
use core::iter::{
63-
FromIterator, InPlaceIterable, SourceIter, TrustedLen,
63+
FromIterator, TrustedLen,
6464
};
6565
use core::marker::PhantomData;
6666
use core::mem::{self, ManuallyDrop, MaybeUninit};
@@ -101,6 +101,8 @@ use self::is_zero::IsZero;
101101

102102
mod is_zero;
103103

104+
mod source_iter_marker;
105+
104106
/// A contiguous growable array type, written `Vec<T>` but pronounced 'vector'.
105107
///
106108
/// # Examples
@@ -2356,109 +2358,6 @@ impl<T> SpecFromIter<T, IntoIter<T>> for Vec<T> {
23562358
}
23572359
}
23582360

2359-
fn write_in_place_with_drop<T>(
2360-
src_end: *const T,
2361-
) -> impl FnMut(InPlaceDrop<T>, T) -> Result<InPlaceDrop<T>, !> {
2362-
move |mut sink, item| {
2363-
unsafe {
2364-
// the InPlaceIterable contract cannot be verified precisely here since
2365-
// try_fold has an exclusive reference to the source pointer
2366-
// all we can do is check if it's still in range
2367-
debug_assert!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation");
2368-
ptr::write(sink.dst, item);
2369-
sink.dst = sink.dst.add(1);
2370-
}
2371-
Ok(sink)
2372-
}
2373-
}
2374-
2375-
/// Specialization marker for collecting an iterator pipeline into a Vec while reusing the
2376-
/// source allocation, i.e. executing the pipeline in place.
2377-
///
2378-
/// The SourceIter parent trait is necessary for the specializing function to access the allocation
2379-
/// which is to be reused. But it is not sufficient for the specialization to be valid. See
2380-
/// additional bounds on the impl.
2381-
#[rustc_unsafe_specialization_marker]
2382-
trait SourceIterMarker: SourceIter<Source: AsIntoIter> {}
2383-
2384-
// The std-internal SourceIter/InPlaceIterable traits are only implemented by chains of
2385-
// Adapter<Adapter<Adapter<IntoIter>>> (all owned by core/std). Additional bounds
2386-
// on the adapter implementations (beyond `impl<I: Trait> Trait for Adapter<I>`) only depend on other
2387-
// traits already marked as specialization traits (Copy, TrustedRandomAccess, FusedIterator).
2388-
// I.e. the marker does not depend on lifetimes of user-supplied types. Modulo the Copy hole, which
2389-
// several other specializations already depend on.
2390-
impl<T> SourceIterMarker for T where T: SourceIter<Source: AsIntoIter> + InPlaceIterable {}
2391-
2392-
impl<T, I> SpecFromIter<T, I> for Vec<T>
2393-
where
2394-
I: Iterator<Item = T> + SourceIterMarker,
2395-
{
2396-
default fn from_iter(mut iterator: I) -> Self {
2397-
// Additional requirements which cannot expressed via trait bounds. We rely on const eval
2398-
// instead:
2399-
// a) no ZSTs as there would be no allocation to reuse and pointer arithmetic would panic
2400-
// b) size match as required by Alloc contract
2401-
// c) alignments match as required by Alloc contract
2402-
if mem::size_of::<T>() == 0
2403-
|| mem::size_of::<T>()
2404-
!= mem::size_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
2405-
|| mem::align_of::<T>()
2406-
!= mem::align_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
2407-
{
2408-
// fallback to more generic implementations
2409-
return SpecFromIterNested::from_iter(iterator);
2410-
}
2411-
2412-
let (src_buf, src_ptr, dst_buf, dst_end, cap) = unsafe {
2413-
let inner = iterator.as_inner().as_into_iter();
2414-
(
2415-
inner.buf.as_ptr(),
2416-
inner.ptr,
2417-
inner.buf.as_ptr() as *mut T,
2418-
inner.end as *const T,
2419-
inner.cap,
2420-
)
2421-
};
2422-
2423-
// use try-fold since
2424-
// - it vectorizes better for some iterator adapters
2425-
// - unlike most internal iteration methods, it only takes a &mut self
2426-
// - it lets us thread the write pointer through its innards and get it back in the end
2427-
let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf };
2428-
let sink = iterator
2429-
.try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(dst_end))
2430-
.unwrap();
2431-
// iteration succeeded, don't drop head
2432-
let dst = ManuallyDrop::new(sink).dst;
2433-
2434-
let src = unsafe { iterator.as_inner().as_into_iter() };
2435-
// check if SourceIter contract was upheld
2436-
// caveat: if they weren't we may not even make it to this point
2437-
debug_assert_eq!(src_buf, src.buf.as_ptr());
2438-
// check InPlaceIterable contract. This is only possible if the iterator advanced the
2439-
// source pointer at all. If it uses unchecked access via TrustedRandomAccess
2440-
// then the source pointer will stay in its initial position and we can't use it as reference
2441-
if src.ptr != src_ptr {
2442-
debug_assert!(
2443-
dst as *const _ <= src.ptr,
2444-
"InPlaceIterable contract violation, write pointer advanced beyond read pointer"
2445-
);
2446-
}
2447-
2448-
// drop any remaining values at the tail of the source
2449-
src.drop_remaining();
2450-
// but prevent drop of the allocation itself once IntoIter goes out of scope
2451-
src.forget_allocation();
2452-
2453-
let vec = unsafe {
2454-
let len = dst.offset_from(dst_buf) as usize;
2455-
Vec::from_raw_parts(dst_buf, len, cap)
2456-
};
2457-
2458-
vec
2459-
}
2460-
}
2461-
24622361
impl<'a, T: 'a, I> SpecFromIter<&'a T, I> for Vec<T>
24632362
where
24642363
I: Iterator<Item = &'a T>,
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
use core::iter::{
2+
InPlaceIterable, SourceIter,
3+
};
4+
use core::mem::{self, ManuallyDrop};
5+
use core::ptr::{self};
6+
7+
use super::{Vec, InPlaceDrop, AsIntoIter, SpecFromIter, SpecFromIterNested};
8+
9+
/// Specialization marker for collecting an iterator pipeline into a Vec while reusing the
10+
/// source allocation, i.e. executing the pipeline in place.
11+
///
12+
/// The SourceIter parent trait is necessary for the specializing function to access the allocation
13+
/// which is to be reused. But it is not sufficient for the specialization to be valid. See
14+
/// additional bounds on the impl.
15+
#[rustc_unsafe_specialization_marker]
16+
pub (super) trait SourceIterMarker: SourceIter<Source: AsIntoIter> {}
17+
18+
// The std-internal SourceIter/InPlaceIterable traits are only implemented by chains of
19+
// Adapter<Adapter<Adapter<IntoIter>>> (all owned by core/std). Additional bounds
20+
// on the adapter implementations (beyond `impl<I: Trait> Trait for Adapter<I>`) only depend on other
21+
// traits already marked as specialization traits (Copy, TrustedRandomAccess, FusedIterator).
22+
// I.e. the marker does not depend on lifetimes of user-supplied types. Modulo the Copy hole, which
23+
// several other specializations already depend on.
24+
impl<T> SourceIterMarker for T where T: SourceIter<Source: AsIntoIter> + InPlaceIterable {}
25+
26+
impl<T, I> SpecFromIter<T, I> for Vec<T>
27+
where
28+
I: Iterator<Item = T> + SourceIterMarker,
29+
{
30+
default fn from_iter(mut iterator: I) -> Self {
31+
// Additional requirements which cannot expressed via trait bounds. We rely on const eval
32+
// instead:
33+
// a) no ZSTs as there would be no allocation to reuse and pointer arithmetic would panic
34+
// b) size match as required by Alloc contract
35+
// c) alignments match as required by Alloc contract
36+
if mem::size_of::<T>() == 0
37+
|| mem::size_of::<T>()
38+
!= mem::size_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
39+
|| mem::align_of::<T>()
40+
!= mem::align_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
41+
{
42+
// fallback to more generic implementations
43+
return SpecFromIterNested::from_iter(iterator);
44+
}
45+
46+
let (src_buf, src_ptr, dst_buf, dst_end, cap) = unsafe {
47+
let inner = iterator.as_inner().as_into_iter();
48+
(
49+
inner.buf.as_ptr(),
50+
inner.ptr,
51+
inner.buf.as_ptr() as *mut T,
52+
inner.end as *const T,
53+
inner.cap,
54+
)
55+
};
56+
57+
// use try-fold since
58+
// - it vectorizes better for some iterator adapters
59+
// - unlike most internal iteration methods, it only takes a &mut self
60+
// - it lets us thread the write pointer through its innards and get it back in the end
61+
let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf };
62+
let sink = iterator
63+
.try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(dst_end))
64+
.unwrap();
65+
// iteration succeeded, don't drop head
66+
let dst = ManuallyDrop::new(sink).dst;
67+
68+
let src = unsafe { iterator.as_inner().as_into_iter() };
69+
// check if SourceIter contract was upheld
70+
// caveat: if they weren't we may not even make it to this point
71+
debug_assert_eq!(src_buf, src.buf.as_ptr());
72+
// check InPlaceIterable contract. This is only possible if the iterator advanced the
73+
// source pointer at all. If it uses unchecked access via TrustedRandomAccess
74+
// then the source pointer will stay in its initial position and we can't use it as reference
75+
if src.ptr != src_ptr {
76+
debug_assert!(
77+
dst as *const _ <= src.ptr,
78+
"InPlaceIterable contract violation, write pointer advanced beyond read pointer"
79+
);
80+
}
81+
82+
// drop any remaining values at the tail of the source
83+
src.drop_remaining();
84+
// but prevent drop of the allocation itself once IntoIter goes out of scope
85+
src.forget_allocation();
86+
87+
let vec = unsafe {
88+
let len = dst.offset_from(dst_buf) as usize;
89+
Vec::from_raw_parts(dst_buf, len, cap)
90+
};
91+
92+
vec
93+
}
94+
}
95+
96+
fn write_in_place_with_drop<T>(
97+
src_end: *const T,
98+
) -> impl FnMut(InPlaceDrop<T>, T) -> Result<InPlaceDrop<T>, !> {
99+
move |mut sink, item| {
100+
unsafe {
101+
// the InPlaceIterable contract cannot be verified precisely here since
102+
// try_fold has an exclusive reference to the source pointer
103+
// all we can do is check if it's still in range
104+
debug_assert!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation");
105+
ptr::write(sink.dst, item);
106+
sink.dst = sink.dst.add(1);
107+
}
108+
Ok(sink)
109+
}
110+
}

0 commit comments

Comments
 (0)