1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
//! `Vec` 的就地迭代和收集特化
//!
//! Note: 本文档记录了 Vec 内部结构,以下部分解释了实现细节,最好与本模块的源代码一起阅读。
//!
//! 本模块的特化适用于 `source.adapter().adapter().adapter().collect::<Vec<U>>()` 形式的迭代器
//! 其中 `source` 是从 [`Vec<T>`]、[`Box<[T]>`][box] (通过转换为 `Vec`) 或 [`BinaryHeap<T>`] 获得的拥有迭代器,每个适配器每个步骤消耗一个或多个项 (由 [`InPlaceIterable`] 表示),提供对 `source` 的传递访问 (通过 [`SourceIter`]),从而提供底层分配.
//! 最后,`T` 和 `U` 的布局必须具有相同的大小和对齐方式,目前通过 const eval 而不是专门的 [`SpecFromIter`] 实现中的 trait bounds 来确保的。
//!
//! [`BinaryHeap<T>`]: crate::collections::BinaryHeap
//! [box]: crate::boxed::Box
//!
//! 通过扩展,在其 `FromIterator` 实现中内部使用 `collect::<Vec<_>>()` 的其他一些集合也从中受益。
//!
//! 对底层源的访问通过私有 [`AsVecIntoIter`] trait 进行进一步的间接层,以隐藏其他集合可能在内部使用 `vec::IntoIter` 的实现细节。
//!
//! 就地迭代取决于几个不安全的 traits 的交互,迭代器管道中多个部分的实现细节,并且通常需要跨多个结构体进行整体推理,因为迭代器是协作执行的,而不是让中央 evaluator/visitor 结构执行所有迭代器组件。
//!
//!
//! # 读取和写入相同的分配
//!
//! 就其本质而言,就地收集意味着迭代器的 reader 和 writer 端使用相同的分配。由于 `try_fold()` (在 [`SpecInPlaceCollect`] 中使用) 在迭代期间需要对迭代器的引用,这意味着我们不能交替读取值和获取要写入的引用。
//! 相反,必须在 reader 和 writer 端使用裸指针。
//!
//! [`InPlaceIterable`] 要求确保写入操作永远不会破坏尚未读取的项。
//!
//! # 布局约束
//!
//! [`Allocator`] 要求 `allocate()` 和 `deallocate()` 具有匹配的对齐方式和大小。
//! 此外,这种特化对于 ZST 没有意义,因为不需要避免重新分配,而且它会使指针运算更加困难。
//!
//! [`Allocator`]: core::alloc::Allocator
//!
//! # Drop- 和 panic 安全
//!
//! 迭代可能会出现 panic,需要丢弃已写入的部分以及源的其余部分。迭代也可以保留一些必须丢弃的未消耗的源项。
//! 所有这些丢弃进而会导致 panic,然后必须泄漏分配或中止,以避免双重丢弃。
//!
//! 这由 sink 项 (`U`) 的 [`InPlaceDrop`] 守卫和剩余源项 (`T`) 的 [`vec::IntoIter::forget_allocation_drop_remaining()`] 处理。
//!
//! 如果丢弃任何剩余的源 (`T`) panic,则 [`InPlaceDstBufDrop`] 将处理项丢弃已收集的 Z0sink2 项 (`T`) 并释放分配。
//!
//! [`vec::IntoIter::forget_allocation_drop_remaining()`]: super::IntoIter::forget_allocation_drop_remaining()
//!
//! # O(1) 收集
//!
//! 当迭代器实现 [`TrustedRandomAccessNoCoerce`] 以让优化器看到它是一个带有单个 [induction variable] 的计数循环时,主迭代本身会进一步特化。这可以将一些迭代器变成一个 noop,也就是说,它将迭代器从 O(n) 减少到 O(1)。
//! 这种特殊的优化非常易变,并不总是有效,请参见 [#79308]
//!
//! [#79308]: https://github.com/rust-lang/rust/issues/79308
//! [induction variable]: https://en.wikipedia.org/wiki/Induction_variable
//!
//! 由于通过该 trait 的未经检查的访问不会推进 `IntoIter` 的读取指针,这将与上述关于丢弃尾部的要求进行不合理的交互。
//! 但是由于 `IntoIter` 的正常 `Drop` 实现会遇到同样的问题,因此只有在项没有析构函数时才实现 `TrustedRandomAccessNoCoerce` 是正确的。因此,该隐式要求也使特化可以安全地用于就地收集。
//! 请注意,这个安全问题是关于 `impl Drop for IntoIter` 的正确性,而不是 `InPlaceIterable` 的保证。
//!
//! # 适配器实现
//!
//! 适配器的不变量记录在 [`SourceIter`] 和 [`InPlaceIterable`] 中,但是由于多种原因,有时是非本地原因,使它们正确可能相当微妙。
//! 例如,`InPlaceIterable` 对 [`Peekable`] 实现是有效的,除了它是有状态的、可克隆的并且 `IntoIter` 的克隆实现缩短了底层分配,这意味着如果迭代器已被窥视然后被克隆,则不再有足够的空间,从而破坏了不变量 ([#85322])。
//!
//! [#85322]: https://github.com/rust-lang/rust/issues/85322
//! [`Peekable`]: core::iter::Peekable
//!
//! # Examples
//!
//! 通过这种特化优化的一些案例,可以在 `Vec` 基准测试中找到更多:
//!
//! ```rust
//! # #[allow(dead_code)]
//! /// 将 usize vec 转换为 isize one。
//! pub fn cast(vec: Vec<usize>) -> Vec<isize> {
//!   // 不分配、释放或 panic。在 optlevel>=2 时,它不会循环。
//!   // 当然,这种特殊情况可以也应该用 `into_raw_parts` 和 `from_raw_parts` 来代替。
//!   //
//!   vec.into_iter().map(|u| u as isize).collect()
//! }
//! ```
//!
//! ```rust
//! # #[allow(dead_code)]
//! /// 丢弃 `src` 中的剩余项,如果 `T` 和 `U` 的布局匹配,则返回由原始分配支持的空 Vec。
//! /// 否则它返回一个新的空 vec。
//! ///
//! pub fn recycle_allocation<T, U>(src: Vec<T>) -> Vec<U> {
//!   src.into_iter().filter_map(|_| None).collect()
//! }
//! ```
//!
//! ```rust
//! let vec = vec![13usize; 1024];
//! let _ = vec.into_iter()
//!   .enumerate()
//!   .filter_map(|(idx, val)| if idx % 2 == 0 { Some(val+idx) } else {None})
//!   .collect::<Vec<_>>();
//!
//! // 等效于以下内容,但不需要边界检查
//!
//! let mut vec = vec![13usize; 1024];
//! let mut write_idx = 0;
//! for idx in 0..vec.len() {
//!    if idx % 2 == 0 {
//!       vec[write_idx] = vec[idx] + idx;
//!       write_idx += 1;
//!    }
//! }
//! vec.truncate(write_idx);
//! ```
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
use core::iter::{InPlaceIterable, SourceIter, TrustedRandomAccessNoCoerce};
use core::mem::{self, ManuallyDrop, SizedTypeProperties};
use core::ptr::{self};

use super::{InPlaceDrop, InPlaceDstBufDrop, SpecFromIter, SpecFromIterNested, Vec};

/// 专业化标记,用于在重用源分配时将迭代器管道收集到 Vec 中,即
/// 在适当的位置执行管道。
#[rustc_unsafe_specialization_marker]
pub(super) trait InPlaceIterableMarker {}

impl<T> InPlaceIterableMarker for T where T: InPlaceIterable {}

impl<T, I> SpecFromIter<T, I> for Vec<T>
where
    I: Iterator<Item = T> + SourceIter<Source: AsVecIntoIter> + InPlaceIterableMarker,
{
    default fn from_iter(mut iterator: I) -> Self {
        // 请参见模块文档中的 "布局约束" 部分。
        // 我们在这里依赖常量优化,因为这些条件目前不能表示为 trait bounds
        if T::IS_ZST
            || mem::size_of::<T>()
                != mem::size_of::<<<I as SourceIter>::Source as AsVecIntoIter>::Item>()
            || mem::align_of::<T>()
                != mem::align_of::<<<I as SourceIter>::Source as AsVecIntoIter>::Item>()
        {
            // 回退到更通用的实现
            return SpecFromIterNested::from_iter(iterator);
        }

        let (src_buf, src_ptr, dst_buf, dst_end, cap) = unsafe {
            let inner = iterator.as_inner().as_into_iter();
            (
                inner.buf.as_ptr(),
                inner.ptr,
                inner.buf.as_ptr() as *mut T,
                inner.end as *const T,
                inner.cap,
            )
        };

        // SAFETY: `dst_buf` 和 `dst_end` 是缓冲区的开始和结束。
        let len = unsafe { SpecInPlaceCollect::collect_in_place(&mut iterator, dst_buf, dst_end) };

        let src = unsafe { iterator.as_inner().as_into_iter() };
        // 检查 SourceIter 契约是否得到维护警告:如果不是,我们甚至可能无法做到这一点
        //
        debug_assert_eq!(src_buf, src.buf.as_ptr());
        // 检查 InPlaceIterable 契约。只有迭代器推进了源指针,这才是可能的。
        // 如果它通过 TrustedRandomAccess 使用未经检查的访问,则源指针将停留在其初始位置,我们不能将其用作引用
        //
        if src.ptr != src_ptr {
            debug_assert!(
                unsafe { dst_buf.add(len) as *const _ } <= src.ptr,
                "InPlaceIterable contract violation, write pointer advanced beyond read pointer"
            );
        }

        // 分配的所有权和新的 `T` 值暂时移至 `dst_guard`。
        // 这是安全的,因为 `forget_allocation_drop_remaining` 在任何 panic 发生之前立即忘记分配以避免任何重复释放,然后继续丢弃源尾部的任何剩余值。
        //
        //
        // Note: TrustedRandomIteratorNoCoerce 契约 (由下面的 SpecInPlaceCollect 使用) 不允许对源的这种访问。但是请参见模块文档中的 "O(1) collect" 部分,为什么这仍然可以。
        //
        //
        //
        let dst_guard = InPlaceDstBufDrop { ptr: dst_buf, len, cap };
        src.forget_allocation_drop_remaining();
        mem::forget(dst_guard);

        let vec = unsafe { Vec::from_raw_parts(dst_buf, len, cap) };

        vec
    }
}

fn write_in_place_with_drop<T>(
    src_end: *const T,
) -> impl FnMut(InPlaceDrop<T>, T) -> Result<InPlaceDrop<T>, !> {
    move |mut sink, item| {
        unsafe {
            // 这里的 InPlaceIterable 契约无法精确验证,因为 try_fold 对源指针有一个唯一的引用,我们所能做的就是检查它是否仍在范围内
            //
            //
            debug_assert!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation");
            ptr::write(sink.dst, item);
            // 由于这会执行用户代码,这可能会导致 panic,因此我们必须在每一步之后 bump 指针。
            //
            sink.dst = sink.dst.add(1);
        }
        Ok(sink)
    }
}

/// 一个用于保存就地迭代收集循环的专用实现的 Helper trait
trait SpecInPlaceCollect<T, I>: Iterator<Item = T> {
    /// 将迭代器 (`self`) 收集到目标缓冲区 (`dst`) 中并返回收集的项数。`end` 是分配的最后一个可写元素,用于边界检查。
    ///
    /// 这个方法是专门的,它的一个实现使用 `Iterator::__iterator_get_unchecked` 调用,`TrustedRandomAccessNoCoerce` 绑定在 `I` 上,这意味着这个方法的调用者必须考虑 trait 的安全条件。
    ///
    ///
    ///
    ///
    unsafe fn collect_in_place(&mut self, dst: *mut T, end: *const T) -> usize;
}

impl<T, I> SpecInPlaceCollect<T, I> for I
where
    I: Iterator<Item = T>,
{
    #[inline]
    default unsafe fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize {
        // 使用 try-fold,因为
        // - 对于某些迭代器适配器,它可以更好地进行矢量化
        // - 与大多数内部迭代方法不同,它只需要一个 &mut self
        // - 它让我们把写指针穿进它的内部,最后把它拿回来
        let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf };
        let sink =
            self.try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(end)).unwrap();
        // 迭代成功,不要丢弃 head
        unsafe { ManuallyDrop::new(sink).dst.sub_ptr(dst_buf) }
    }
}

impl<T, I> SpecInPlaceCollect<T, I> for I
where
    I: Iterator<Item = T> + TrustedRandomAccessNoCoerce,
{
    #[inline]
    unsafe fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize {
        let len = self.size();
        let mut drop_guard = InPlaceDrop { inner: dst_buf, dst: dst_buf };
        for i in 0..len {
            // 安全性: InplaceIterable 契约保证,对于我们读取的每个元素,底层存储中的一个插槽将被释放,我们可以立即写回结果。
            //
            //
            unsafe {
                let dst = dst_buf.add(i);
                debug_assert!(dst as *const _ <= end, "InPlaceIterable contract violation");
                ptr::write(dst, self.__iterator_get_unchecked(i));
                // 由于这会执行用户代码,这可能会导致 panic,因此我们必须在每一步之后 bump 指针。
                //
                drop_guard.dst = dst.add(1);
            }
        }
        mem::forget(drop_guard);
        len
    }
}

/// 用于就地迭代特化的内部助手 trait。
///
/// 目前这仅由 [`vec::IntoIter`] 实现 - 返回对自身的引用 - 并且 [`binary_heap::IntoIter`] 将返回对其内部表示的引用。
///
/// 由于这是一个内部 trait,它隐藏了 `binary_heap::IntoIter` 在内部使用 `vec::IntoIter` 的实现细节。
///
/// [`vec::IntoIter`]: super::IntoIter
/// [`binary_heap::IntoIter`]: crate::collections::binary_heap::IntoIter
///
/// # Safety
///
/// 就地迭代依赖于 `vec::IntoIter` 的实现细节,最重要的是它不会在迭代过程中创建对整个分配的引用,只是创建裸指针
///
///
///
#[rustc_specialization_trait]
pub(crate) unsafe trait AsVecIntoIter {
    type Item;
    fn as_into_iter(&mut self) -> &mut super::IntoIter<Self::Item>;
}