]> git.proxmox.com Git - rustc.git/blame - src/doc/nomicon/src/vec-drain.md
New upstream version 1.31.0~beta.4+dfsg1
[rustc.git] / src / doc / nomicon / src / vec-drain.md
CommitLineData
8bb4bdeb 1# Drain
c1a9b12d
SL
2
3Let's move on to Drain. Drain is largely the same as IntoIter, except that
4instead of consuming the Vec, it borrows the Vec and leaves its allocation
5untouched. For now we'll only implement the "basic" full-range version.
6
7```rust,ignore
8use std::marker::PhantomData;
9
10struct Drain<'a, T: 'a> {
11 // Need to bound the lifetime here, so we do it with `&'a mut Vec<T>`
12 // because that's semantically what we contain. We're "just" calling
13 // `pop()` and `remove(0)`.
abe05a73 14 vec: PhantomData<&'a mut Vec<T>>,
c1a9b12d
SL
15 start: *const T,
16 end: *const T,
17}
18
19impl<'a, T> Iterator for Drain<'a, T> {
20 type Item = T;
21 fn next(&mut self) -> Option<T> {
22 if self.start == self.end {
23 None
24```
25
26-- wait, this is seeming familiar. Let's do some more compression. Both
27IntoIter and Drain have the exact same structure, let's just factor it out.
28
29```rust
30struct RawValIter<T> {
31 start: *const T,
32 end: *const T,
33}
34
35impl<T> RawValIter<T> {
36 // unsafe to construct because it has no associated lifetimes.
37 // This is necessary to store a RawValIter in the same struct as
38 // its actual allocation. OK since it's a private implementation
39 // detail.
40 unsafe fn new(slice: &[T]) -> Self {
41 RawValIter {
42 start: slice.as_ptr(),
43 end: if slice.len() == 0 {
44 // if `len = 0`, then this is not actually allocated memory.
45 // Need to avoid offsetting because that will give wrong
46 // information to LLVM via GEP.
47 slice.as_ptr()
48 } else {
49 slice.as_ptr().offset(slice.len() as isize)
50 }
51 }
52 }
53}
54
55// Iterator and DoubleEndedIterator impls identical to IntoIter.
56```
57
58And IntoIter becomes the following:
59
60```rust,ignore
61pub struct IntoIter<T> {
62 _buf: RawVec<T>, // we don't actually care about this. Just need it to live.
63 iter: RawValIter<T>,
64}
65
66impl<T> Iterator for IntoIter<T> {
67 type Item = T;
68 fn next(&mut self) -> Option<T> { self.iter.next() }
69 fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
70}
71
72impl<T> DoubleEndedIterator for IntoIter<T> {
73 fn next_back(&mut self) -> Option<T> { self.iter.next_back() }
74}
75
76impl<T> Drop for IntoIter<T> {
77 fn drop(&mut self) {
78 for _ in &mut self.iter {}
79 }
80}
81
82impl<T> Vec<T> {
83 pub fn into_iter(self) -> IntoIter<T> {
84 unsafe {
85 let iter = RawValIter::new(&self);
86
87 let buf = ptr::read(&self.buf);
88 mem::forget(self);
89
90 IntoIter {
91 iter: iter,
92 _buf: buf,
93 }
94 }
95 }
96}
97```
98
99Note that I've left a few quirks in this design to make upgrading Drain to work
100with arbitrary subranges a bit easier. In particular we *could* have RawValIter
101drain itself on drop, but that won't work right for a more complex Drain.
102We also take a slice to simplify Drain initialization.
103
104Alright, now Drain is really easy:
105
106```rust,ignore
107use std::marker::PhantomData;
108
109pub struct Drain<'a, T: 'a> {
110 vec: PhantomData<&'a mut Vec<T>>,
111 iter: RawValIter<T>,
112}
113
114impl<'a, T> Iterator for Drain<'a, T> {
115 type Item = T;
116 fn next(&mut self) -> Option<T> { self.iter.next() }
117 fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
118}
119
120impl<'a, T> DoubleEndedIterator for Drain<'a, T> {
121 fn next_back(&mut self) -> Option<T> { self.iter.next_back() }
122}
123
124impl<'a, T> Drop for Drain<'a, T> {
125 fn drop(&mut self) {
126 for _ in &mut self.iter {}
127 }
128}
129
130impl<T> Vec<T> {
131 pub fn drain(&mut self) -> Drain<T> {
c1a9b12d 132 unsafe {
e9174d1e
SL
133 let iter = RawValIter::new(&self);
134
135 // this is a mem::forget safety thing. If Drain is forgotten, we just
136 // leak the whole Vec's contents. Also we need to do this *eventually*
137 // anyway, so why not do it now?
138 self.len = 0;
139
c1a9b12d 140 Drain {
e9174d1e 141 iter: iter,
c1a9b12d
SL
142 vec: PhantomData,
143 }
144 }
145 }
146}
147```
148
149For more details on the `mem::forget` problem, see the
150[section on leaks][leaks].
151
152[leaks]: leaking.html