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}