push_while_ref/lib.rs
1//! A crate to enable holding a reference while still being able to push.
2//! This is possible if you have another lifetime just for storing data
3//! (here called `Owner`).
4//!
5//! The data that is inserted needs to not move in memory, because if the container (Vec, HashMap...)
6//! needs to reallocate that would invalidate the reference.
7//! this is garantie is give by the trait `StaticType`.
8//!
9//! # Example pushing
10//! ```
11//! use push_while_ref::{VecOwner, VecChild};
12//!
13//! let mut vec = VecOwner::new();
14//! let mut vec = vec.child();
15//! let v1 = vec.push(Box::new(10));
16//! let v2 = vec.push(Box::new(20));
17//! assert_eq!(*v1, 10);
18//! assert_eq!(*v2, 20);
19//! ```
20//!
21//! # Example inserting
22//! ```
23//! use push_while_ref::{HashMapOwner, HashMapChild};
24//!
25//! let mut map = HashMapOwner::new();
26//! let mut map = map.child();
27//! let v1 = map.insert("10", Box::new(10));
28//! let v2 = map.insert("20", Box::new(20));
29//! assert_eq!(*v1, 10);
30//! assert_eq!(*v2, 20);
31//! ```
32
33
34use std::hash::Hash;
35use std::borrow::Borrow;
36use std::collections::HashMap;
37
38#[derive(Debug)]
39pub struct VecOwner<T>(Vec<T>);
40
41impl<T> VecOwner<T>
42where T: StaticType {
43
44 /// Create a new empty vector.
45 pub fn new() -> Self {
46 Self(vec![])
47 }
48
49 /// you need to make sure that the pointer is not used after
50 /// VecOwner goes out of scope and that the ptr is only used to cast to a reference
51 #[inline]
52 pub(crate) fn push(&mut self, v: T) -> *const T::Ref {
53 let ptr = v.ref_ptr();
54 self.0.push(v);
55
56 debug_assert_eq!(
57 self.0.last().unwrap().ref_ptr(),
58 ptr,
59 "Trait promises we're not uphold"
60 );
61
62 ptr
63 }
64
65 pub fn child(&mut self) -> VecChild<'_, T> {
66 VecChild(self)
67 }
68
69}
70
71#[derive(Debug)]
72pub struct VecChild<'a, T>(&'a mut VecOwner<T>);
73
74impl<'a, T> VecChild<'a, T>
75where T: StaticType {
76
77 /// pushes the value to the owner
78 /// and returns a reference to the inserted value
79 /// without using the current lifetime
80 ///
81 /// ```
82 /// # use push_while_ref::{VecOwner, VecChild};
83 /// let mut vec = VecOwner::new();
84 /// let mut vec = vec.child();
85 /// let v1 = vec.push(Box::new(10));
86 /// let v2 = vec.push(Box::new(20));
87 /// assert_eq!(*v1, 10);
88 /// assert_eq!(*v2, 20);
89 /// ```
90 pub fn push(&mut self, v: T) -> &'a T::Ref {
91 let ptr = self.0.push(v);
92 // safe because ptr does not live longer than VecOwner
93 unsafe { &*ptr }
94 }
95}
96
97
98#[derive(Debug)]
99pub struct HashMapOwner<K, T>(HashMap<K, T>);
100
101impl<K, T> HashMapOwner<K, T>
102where
103 K: Hash + Eq + Clone,
104 T: StaticType {
105
106 pub fn new() -> Self {
107 Self(HashMap::new())
108 }
109
110 pub(crate) fn as_ref(&self) -> &HashMap<K, T> {
111 &self.0
112 }
113
114 /// you need to make sure that the pointer is not used after
115 /// VecOwner goes out of scope and that the ptr is only used to cast to a reference
116 #[inline]
117 pub(crate) fn try_insert(&mut self, key: K, v: T) -> Option<*const T::Ref> {
118 // check if key already contained in HashMap
119 // this needs to be done because else we would invalid the promise we give
120 if self.0.contains_key(&key) {
121 return None
122 }
123
124 let ptr = v.ref_ptr();
125
126 // check that traits are upholding their promise
127 if cfg!(debug_assertions) {
128 self.0.insert(key.clone(), v);
129 let v = self.0.get(&key).unwrap();
130 assert_eq!(ptr, v.ref_ptr(), "Trait promises we're not uphold");
131
132 // we expect the trait to upholde their promise
133 } else {
134 self.0.insert(key, v);
135 }
136
137 Some(ptr)
138 }
139
140 /// Creates a `HashMapChild` which will allow to interact with the HashMap.
141 pub fn child(&mut self) -> HashMapChild<'_, K, T> {
142 HashMapChild(self)
143 }
144
145}
146
147
148#[derive(Debug)]
149pub struct HashMapChild<'a, K, T>(&'a mut HashMapOwner<K, T>);
150
151impl<'a, K, T> HashMapChild<'a, K, T>
152where
153 K: Hash + Eq + Clone,
154 T: StaticType {
155
156 /// Returns `true` if the map contains a value for the specified key.
157 ///
158 /// ```
159 /// # use push_while_ref::{HashMapOwner, HashMapChild};
160 /// let mut map = HashMapOwner::new();
161 /// let mut map = map.child();
162 /// let value = map.insert("10".to_string(), Box::new(10));
163 /// assert!(map.contains_key("10"));
164 /// ```
165 pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
166 where
167 K: Borrow<Q>,
168 Q: Hash + Eq {
169 self.0.as_ref().contains_key(k)
170 }
171
172 /// Tries to insert key and value
173 /// if key already exists returns None
174 ///
175 /// Else returns a reference to the inserted value
176 /// without using the current lifetime
177 ///
178 /// ```
179 /// # use push_while_ref::{HashMapOwner, HashMapChild};
180 /// let mut map = HashMapOwner::new();
181 /// let mut map = map.child();
182 /// let v1 = map.try_insert("10", Box::new(10)).unwrap();
183 /// let v2 = map.try_insert("20", Box::new(20)).unwrap();
184 /// assert_eq!(*v1, 10);
185 /// assert_eq!(*v2, 20);
186 /// ```
187 pub fn try_insert(&mut self, key: K, v: T) -> Option<&'a T::Ref> {
188 self.0.try_insert(key, v)
189 .map(|ptr| {
190 // safe because ref does not live longer than HashMapOwner
191 unsafe { &*ptr }
192 })
193 }
194
195 /// Insert key and value to the owner
196 ///
197 /// Else returns a reference to the inserted value
198 /// without using the current lifetime
199 ///
200 /// # Panics
201 /// Panics if key already exists
202 ///
203 /// ```
204 /// # use push_while_ref::{HashMapOwner, HashMapChild};
205 /// let mut map = HashMapOwner::new();
206 /// let mut map = map.child();
207 /// let v1 = map.insert("10", Box::new(10));
208 /// let v2 = map.insert("20", Box::new(20));
209 /// assert_eq!(*v1, 10);
210 /// assert_eq!(*v2, 20);
211 /// ```
212 pub fn insert(&mut self, key: K, v: T) -> &'a T::Ref {
213 let ptr = self.0.try_insert(key, v).expect("Key already exists");
214 // safe because ref does not live longer than HashMapOwner
215 unsafe { &*ptr }
216 }
217
218}
219
220
221/// A value that is fixed in memory.
222///
223/// If you implement this
224/// you need to guarantee that Self and Ref does not move in memory
225///
226/// Most probably it should be allocated on the heap
227pub unsafe trait StaticType {
228 type Ref: ?Sized;
229
230 /// the caller of ref_ptr promises to
231 /// not use the ptr after Self goes out of scope
232 /// and to use the ptr only to cast to a references
233 fn ref_ptr(&self) -> *const Self::Ref;
234}
235
236// unsafe impl<T> StaticType for Vec<T> {
237// type Ref = [T];
238
239// fn ref_ptr(&self) -> *const Self::Ref {
240// &*self
241// }
242
243// fn ref(&self) -> &Self::Ref {
244// &self
245// }
246// }
247
248unsafe impl<T: ?Sized> StaticType for Box<T> {
249 type Ref = T;
250
251 #[inline]
252 fn ref_ptr(&self) -> *const Self::Ref {
253 &**self
254 }
255}
256
257
258#[cfg(test)]
259mod tests {
260
261 use super::*;
262
263 fn is_send<T: Send>() {}
264 fn is_sync<T: Sync>() {}
265
266 #[test]
267 fn insert_to_vec() {
268 let mut v = VecOwner::new();
269 let mut v = v.child();
270 let s1 = v.push(Box::new(String::from("hey")));
271 let s2 = v.push(Box::new(String::from("hey 2")));
272 assert_eq!("hey", s1);
273 assert_eq!("hey 2", s2);
274 }
275
276 #[test]
277 #[should_panic]
278 fn insert_twice() {
279
280 let mut files = HashMapOwner::new();
281 let mut files = files.child();
282
283 files.insert("abc", vec![1].into_boxed_slice());
284 files.insert("abc", vec![1].into_boxed_slice());
285
286 }
287
288 #[test]
289 fn test_auto_traits() {
290 type Basic = Box<usize>;
291 is_send::<VecOwner<Basic>>();
292 is_sync::<VecOwner<Basic>>();
293 is_send::<VecChild<Basic>>();
294 is_sync::<VecChild<Basic>>();
295 is_send::<HashMapOwner<Basic, Basic>>();
296 is_sync::<HashMapOwner<Basic, Basic>>();
297 is_send::<HashMapChild<Basic, Basic>>();
298 is_sync::<HashMapChild<Basic, Basic>>();
299 }
300
301}