orx_pinned_vec/imp_vec.rs
1use crate::PinnedVec;
2use core::ops::{Deref, DerefMut};
3use core::{cell::UnsafeCell, marker::PhantomData};
4use orx_self_or::SoM;
5
6/// `ImpVec`, stands for immutable push vector 👿, is a data structure which allows appending elements with a shared reference.
7///
8/// Specifically, it extends vector capabilities with the following three methods:
9///
10/// * `fn imp_push(&self, value: T)`
11/// * `fn imp_extend_from_slice(&self, slice: &[T])`
12/// * `fn imp_push_get_ref(&self, value: T) -> &T`
13///
14/// Note that both of these methods can be called with `&self` rather than `&mut self`.
15/// This is safe since growth does not cause memory locations of existing elements of pinned vectors.
16///
17/// # Examples
18///
19/// A common use case is when we want to iterate over existing elements,
20/// and add new elements to the same vector.
21///
22/// The following code does not compile:
23///
24/// ```ignore
25/// fn add_doubles_of_evens(vec: &mut Vec<u32>) {
26/// for i in vec.iter().copied() {
27/// if i.is_multiple_of(2) {
28/// let doubled = 2 * i;
29/// vec.push(doubled); // cannot borrow `*vec` as mutable because it is also borrowed as immutable
30/// }
31/// }
32/// }
33///
34/// let mut vec = vec![9, 10, 11];
35///
36/// add_doubles_of_evens(&mut vec);
37///
38/// assert_eq!(&vec, &[9, 10, 11, 20]);
39/// ```
40///
41/// However, this would safely work with a pinned vector.
42/// `SplitVec` is one pinned vector implementation, see `orx-split-vec` crate for details.
43///
44/// ```ignore
45/// use orx_pinned_vec::*;
46///
47/// fn add_doubles_of_evens(vec: &mut SplitVec<u32>) {
48/// let vec = vec.as_imp_vec();
49/// for i in vec.iter().copied() {
50/// if i.is_multiple_of(2) {
51/// let doubled = 2 * i;
52/// vec.imp_push(doubled);
53/// }
54/// }
55/// }
56///
57/// let mut vec = SplitVec::new();
58/// vec.extend_from_slice(&[9, 10, 11]);
59///
60/// add_doubles_of_evens(&mut vec);
61///
62/// assert_eq!(&vec, &[9, 10, 11, 20]);
63/// ```
64pub struct ImpVec<T, P, S>
65where
66 P: PinnedVec<T>,
67 S: SoM<P>,
68{
69 pinned_vec: UnsafeCell<S>,
70 phantom: PhantomData<(T, P)>,
71}
72
73impl<T, P, S> ImpVec<T, P, S>
74where
75 P: PinnedVec<T>,
76 S: SoM<P>,
77{
78 // helper
79
80 #[allow(clippy::mut_from_ref)]
81 #[inline(always)]
82 fn pinned_mut(&self) -> &mut P {
83 // SAFETY: `ImpVec` does not implement Send or Sync.
84 // Further `imp_push` and `imp_extend_from_slice` methods are safe to call with a shared reference due to pinned vector guarantees.
85 // All other calls to this internal method require a mutable reference.
86 unsafe { &mut *self.pinned_vec.get() }.get_mut()
87 }
88
89 #[inline(always)]
90 fn pinned(&self) -> &P {
91 // SAFETY: `ImpVec` does not implement Send or Sync.
92 // Further `imp_push` and `imp_extend_from_slice` methods are safe to call with a shared reference due to pinned vector guarantees.
93 // All other calls to this internal method require a mutable reference.
94 unsafe { &*self.pinned_vec.get() }.get_ref()
95 }
96
97 // new
98
99 pub(super) fn new(pinned_vec: S) -> Self {
100 Self {
101 pinned_vec: pinned_vec.into(),
102 phantom: PhantomData,
103 }
104 }
105
106 // api
107
108 /// Returns back the inner pinned vector that this `ImpVec` is created from.
109 pub fn into_inner(self) -> S {
110 self.pinned_vec.into_inner()
111 }
112
113 /// Pushes the `value` to the vector.
114 /// This method differs from the `push` method with the required reference.
115 /// Unlike `push`, `imp_push` allows to push the element with a shared reference.
116 ///
117 /// # Example
118 ///
119 /// ```rust ignore
120 /// use pinned_vec::*;
121 ///
122 /// let mut split_vec = SplitVec::new();
123 ///
124 /// let mut vec = split_vec.as_imp_vec();
125 ///
126 /// // regular push with &mut self
127 /// vec.push(42);
128 ///
129 /// // hold on to a reference to the first element
130 /// let ref_to_first = &vec[0];
131 /// assert_eq!(ref_to_first, &42);
132 ///
133 /// // imp_push with &self
134 /// vec.imp_push(7);
135 ///
136 /// // due to `PinnedVec` guarantees, this push will never invalidate prior references
137 /// assert_eq!(ref_to_first, &42);
138 /// ```
139 #[inline(always)]
140 pub fn imp_push(&self, value: T) {
141 self.pinned_mut().push(value);
142 }
143
144 /// Pushes the `value` to the vector and returns a reference to it.
145 ///
146 /// It is the composition of [`vec.imp_push(value)`] call followed by `&vec[vec.len() - 1]`.
147 ///
148 /// [`vec.imp_push(value)`]: crate::ImpVec::imp_push
149 ///
150 /// # Examples
151 ///
152 /// This method provides a shorthand for the following common use case.
153 ///
154 /// ```rust ignore
155 /// use pinned_vec::*;
156 ///
157 /// let mut split_vec = SplitVec::new();
158 ///
159 /// let mut vec = split_vec.as_imp_vec();
160 ///
161 /// vec.imp_push('a');
162 /// let a = &vec[vec.len() - 1];
163 /// assert_eq!(a, &'a');
164 ///
165 /// // or with imp_push_get_ref
166 ///
167 /// let b = vec.imp_push_get_ref('b');
168 /// assert_eq!(b, &'b');
169 /// ```
170 #[inline(always)]
171 pub fn imp_push_get_ref(&self, value: T) -> &T {
172 let pinned = self.pinned_mut();
173 pinned.push(value);
174 &pinned[pinned.len() - 1]
175 }
176
177 /// Extends the vector with the given `slice`.
178 /// This method differs from the `extend_from_slice` method with the required reference.
179 /// Unlike `extend_from_slice`, `imp_extend_from_slice` allows to push the element with a shared reference.
180 ///
181 /// # Example
182 ///
183 /// ```rust ignore
184 /// use pinned_vec::*;
185 ///
186 /// let mut split_vec = SplitVec::new();
187 ///
188 /// // regular extend_from_slice with &mut self
189 /// vec.extend_from_slice(&[42]);
190 ///
191 /// // hold on to a reference to the first element
192 /// let ref_to_first = &vec[0];
193 /// assert_eq!(ref_to_first, &42);
194 ///
195 /// // imp_extend_from_slice with &self
196 /// vec.imp_extend_from_slice(&[0, 1, 2, 3]);
197 /// assert_eq!(vec.len(), 5);
198 ///
199 /// // due to `PinnedVec` guarantees, this extend will never invalidate prior references
200 /// assert_eq!(ref_to_first, &42);
201 /// ```
202 pub fn imp_extend_from_slice(&self, slice: &[T])
203 where
204 T: Clone,
205 {
206 self.pinned_mut().extend_from_slice(slice);
207 }
208}
209
210impl<T, P, S> Deref for ImpVec<T, P, S>
211where
212 P: PinnedVec<T>,
213 S: SoM<P>,
214{
215 type Target = P;
216 fn deref(&self) -> &Self::Target {
217 self.pinned()
218 }
219}
220
221impl<T, P, S> DerefMut for ImpVec<T, P, S>
222where
223 P: PinnedVec<T>,
224 S: SoM<P>,
225{
226 fn deref_mut(&mut self) -> &mut Self::Target {
227 self.pinned_mut()
228 }
229}