1use std::{mem, ptr};
23use smallvec::{Array, SmallVec};
4use thin_vec::ThinVec;
56pub trait FlatMapInPlace<T>: Sized {
7fn flat_map_in_place<F, I>(&mut self, f: F)
8where
9F: FnMut(T) -> I,
10 I: IntoIterator<Item = T>;
11}
1213// The implementation of this method is syntactically identical for all the
14// different vector types.
15macro_rules!flat_map_in_place {
16 ($vec:ident $( where T: $bound:path)?) => {
17fn flat_map_in_place<F, I>(&mut self, mut f: F)
18where
19F: FnMut(T) -> I,
20 I: IntoIterator<Item = T>,
21 {
22struct LeakGuard<'a, T $(: $bound)?>(&'a mut $vec<T>);
2324impl<'a, T $(: $bound)?> Drop for LeakGuard<'a, T> {
25fn drop(&mut self) {
26unsafe {
27self.0.set_len(0); // make sure we just leak elements in case of panic
28}
29 }
30 }
3132let this = LeakGuard(self);
3334let mut read_i = 0;
35let mut write_i = 0;
36unsafe {
37while read_i < this.0.len() {
38// move the read_i'th item out of the vector and map it
39 // to an iterator
40let e = ptr::read(this.0.as_ptr().add(read_i));
41let iter = f(e).into_iter();
42 read_i += 1;
4344for e in iter {
45if write_i < read_i {
46 ptr::write(this.0.as_mut_ptr().add(write_i), e);
47 write_i += 1;
48 } else {
49// If this is reached we ran out of space
50 // in the middle of the vector.
51 // However, the vector is in a valid state here,
52 // so we just do a somewhat inefficient insert.
53this.0.insert(write_i, e);
5455 read_i += 1;
56 write_i += 1;
57 }
58 }
59 }
6061// write_i tracks the number of actually written new items.
62this.0.set_len(write_i);
6364// The ThinVec is in a sane state again. Prevent the LeakGuard from leaking the data.
65mem::forget(this);
66 }
67 }
68 };
69}
7071impl<T> FlatMapInPlace<T> for Vec<T> {
72flat_map_in_place!(Vec);
73}
7475impl<T, A: Array<Item = T>> FlatMapInPlace<T> for SmallVec<A> {
76flat_map_in_place!(SmallVec where T: Array);
77}
7879impl<T> FlatMapInPlace<T> for ThinVec<T> {
80flat_map_in_place!(ThinVec);
81}