1use super::super::plumbing::*;
2use std::marker::PhantomData;
3use std::mem::MaybeUninit;
4use std::ptr;
5use std::slice;
67pub(super) struct CollectConsumer<'c, T: Send> {
8/// A slice covering the target memory, not yet initialized!
9target: &'c mut [MaybeUninit<T>],
10}
1112impl<'c, T: Send + 'c> CollectConsumer<'c, T> {
13/// The target memory is considered uninitialized, and will be
14 /// overwritten without reading or dropping existing values.
15pub(super) fn new(target: &'c mut [MaybeUninit<T>]) -> Self {
16 CollectConsumer { target }
17 }
18}
1920/// CollectResult represents an initialized part of the target slice.
21///
22/// This is a proxy owner of the elements in the slice; when it drops,
23/// the elements will be dropped, unless its ownership is released before then.
24#[must_use]
25pub(super) struct CollectResult<'c, T> {
26/// A slice covering the target memory, initialized up to our separate `len`.
27target: &'c mut [MaybeUninit<T>],
28/// The current initialized length in `target`
29len: usize,
30/// Lifetime invariance guarantees that the data flows from consumer to result,
31 /// especially for the `scope_fn` callback in `Collect::with_consumer`.
32invariant_lifetime: PhantomData<&'c mut &'c mut [T]>,
33}
3435unsafe impl<'c, T> Send for CollectResult<'c, T> where T: Send {}
3637impl<'c, T> CollectResult<'c, T> {
38/// The current length of the collect result
39pub(super) fn len(&self) -> usize {
40self.len
41 }
4243/// Release ownership of the slice of elements, and return the length
44pub(super) fn release_ownership(mut self) -> usize {
45let ret = self.len;
46self.len = 0;
47 ret
48 }
49}
5051impl<'c, T> Drop for CollectResult<'c, T> {
52fn drop(&mut self) {
53// Drop the first `self.len` elements, which have been recorded
54 // to be initialized by the folder.
55unsafe {
56// TODO: use `MaybeUninit::slice_as_mut_ptr`
57let start = self.target.as_mut_ptr() as *mut T;
58 ptr::drop_in_place(slice::from_raw_parts_mut(start, self.len));
59 }
60 }
61}
6263impl<'c, T: Send + 'c> Consumer<T> for CollectConsumer<'c, T> {
64type Folder = CollectResult<'c, T>;
65type Reducer = CollectReducer;
66type Result = CollectResult<'c, T>;
6768fn split_at(self, index: usize) -> (Self, Self, CollectReducer) {
69let CollectConsumer { target } = self;
7071// Produce new consumers. Normal slicing ensures that the
72 // memory range given to each consumer is disjoint.
73let (left, right) = target.split_at_mut(index);
74 (
75 CollectConsumer::new(left),
76 CollectConsumer::new(right),
77 CollectReducer,
78 )
79 }
8081fn into_folder(self) -> Self::Folder {
82// Create a result/folder that consumes values and writes them
83 // into target. The initial result has length 0.
84CollectResult {
85 target: self.target,
86 len: 0,
87 invariant_lifetime: PhantomData,
88 }
89 }
9091fn full(&self) -> bool {
92false
93}
94}
9596impl<'c, T: Send + 'c> Folder<T> for CollectResult<'c, T> {
97type Result = Self;
9899fn consume(mut self, item: T) -> Self {
100let dest = self
101.target
102 .get_mut(self.len)
103 .expect("too many values pushed to consumer");
104105// Write item and increase the initialized length
106unsafe {
107 dest.as_mut_ptr().write(item);
108self.len += 1;
109 }
110111self
112}
113114fn complete(self) -> Self::Result {
115// NB: We don't explicitly check that the local writes were complete,
116 // but Collect will assert the total result length in the end.
117self
118}
119120fn full(&self) -> bool {
121false
122}
123}
124125/// Pretend to be unindexed for `special_collect_into_vec`,
126/// but we should never actually get used that way...
127impl<'c, T: Send + 'c> UnindexedConsumer<T> for CollectConsumer<'c, T> {
128fn split_off_left(&self) -> Self {
129unreachable!("CollectConsumer must be indexed!")
130 }
131fn to_reducer(&self) -> Self::Reducer {
132 CollectReducer
133 }
134}
135136/// CollectReducer combines adjacent chunks; the result must always
137/// be contiguous so that it is one combined slice.
138pub(super) struct CollectReducer;
139140impl<'c, T> Reducer<CollectResult<'c, T>> for CollectReducer {
141fn reduce(
142self,
143mut left: CollectResult<'c, T>,
144 right: CollectResult<'c, T>,
145 ) -> CollectResult<'c, T> {
146// Merge if the CollectResults are adjacent and in left to right order
147 // else: drop the right piece now and total length will end up short in the end,
148 // when the correctness of the collected result is asserted.
149let left_end = left.target[left.len..].as_ptr();
150if left_end == right.target.as_ptr() {
151let len = left.len + right.release_ownership();
152unsafe {
153 left.target = slice::from_raw_parts_mut(left.target.as_mut_ptr(), len);
154 }
155 left.len = len;
156 }
157 left
158 }
159}