lib.rs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. use std::{
  2. cell::{Cell, Ref, RefCell, RefMut},
  3. fmt::Debug,
  4. marker::PhantomData,
  5. rc::Rc,
  6. };
  7. use bumpalo::Bump;
  8. /// # Example
  9. ///
  10. /// ```compile_fail
  11. /// let data = String::from("hello world");
  12. /// let store = Store::default();
  13. /// let owner = store.owner();
  14. /// let key = owner.insert(&data);
  15. /// drop(data);
  16. /// assert_eq!(*key.read(), "hello world");
  17. /// ```
  18. #[allow(unused)]
  19. fn compile_fail() {}
  20. #[test]
  21. fn reused() {
  22. let store = Store::default();
  23. let first_ptr;
  24. {
  25. let owner = store.owner();
  26. first_ptr = owner.insert(1).raw.data.as_ptr();
  27. drop(owner);
  28. }
  29. {
  30. let owner = store.owner();
  31. let second_ptr = owner.insert(1234).raw.data.as_ptr();
  32. assert_eq!(first_ptr, second_ptr);
  33. drop(owner);
  34. }
  35. }
  36. #[test]
  37. fn leaking_is_ok() {
  38. let data = String::from("hello world");
  39. let store = Store::default();
  40. let key;
  41. {
  42. // create an owner
  43. let owner = store.owner();
  44. // insert data into the store
  45. key = owner.insert(data);
  46. // don't drop the owner
  47. std::mem::forget(owner);
  48. }
  49. assert_eq!(key.try_read().as_deref(), Some(&"hello world".to_string()));
  50. }
  51. #[test]
  52. fn drops() {
  53. let data = String::from("hello world");
  54. let store = Store::default();
  55. let key;
  56. {
  57. // create an owner
  58. let owner = store.owner();
  59. // insert data into the store
  60. key = owner.insert(data);
  61. // drop the owner
  62. }
  63. assert!(key.try_read().is_none());
  64. }
  65. #[test]
  66. fn works() {
  67. let store = Store::default();
  68. let owner = store.owner();
  69. let key = owner.insert(1);
  70. assert_eq!(*key.read(), 1);
  71. }
  72. #[test]
  73. fn insert_while_reading() {
  74. let store = Store::default();
  75. let owner = store.owner();
  76. let key;
  77. {
  78. let data: String = "hello world".to_string();
  79. key = owner.insert(data);
  80. }
  81. let value = key.read();
  82. owner.insert(&1);
  83. assert_eq!(*value, "hello world");
  84. }
  85. #[test]
  86. #[should_panic]
  87. fn panics() {
  88. let store = Store::default();
  89. let owner = store.owner();
  90. let key = owner.insert(1);
  91. drop(owner);
  92. assert_eq!(*key.read(), 1);
  93. }
  94. #[test]
  95. fn fuzz() {
  96. fn maybe_owner_scope(
  97. store: &Store,
  98. valid_keys: &mut Vec<GenerationalBox<String>>,
  99. invalid_keys: &mut Vec<GenerationalBox<String>>,
  100. path: &mut Vec<u8>,
  101. ) {
  102. let branch_cutoff = 5;
  103. let children = if path.len() < branch_cutoff {
  104. rand::random::<u8>() % 4
  105. } else {
  106. rand::random::<u8>() % 2
  107. };
  108. for i in 0..children {
  109. let owner = store.owner();
  110. let key = owner.insert(format!("hello world {path:?}"));
  111. valid_keys.push(key);
  112. path.push(i);
  113. // read all keys
  114. println!("{:?}", path);
  115. for key in valid_keys.iter() {
  116. let value = key.read();
  117. println!("{:?}", value);
  118. assert!(value.starts_with("hello world"));
  119. }
  120. #[cfg(any(debug_assertions, feature = "check_generation"))]
  121. for key in invalid_keys.iter() {
  122. assert!(!key.validate());
  123. }
  124. maybe_owner_scope(store, valid_keys, invalid_keys, path);
  125. invalid_keys.push(valid_keys.pop().unwrap());
  126. path.pop();
  127. }
  128. }
  129. for _ in 0..10 {
  130. let store = Store::default();
  131. maybe_owner_scope(&store, &mut Vec::new(), &mut Vec::new(), &mut Vec::new());
  132. }
  133. }
  134. /// The core Copy state type. The generational box will be dropped when the [Owner] is dropped.
  135. pub struct GenerationalBox<T> {
  136. raw: MemoryLocation,
  137. #[cfg(any(debug_assertions, feature = "check_generation"))]
  138. generation: u32,
  139. _marker: PhantomData<T>,
  140. }
  141. impl<T: 'static> Debug for GenerationalBox<T> {
  142. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  143. #[cfg(any(debug_assertions, feature = "check_generation"))]
  144. f.write_fmt(format_args!(
  145. "{:?}@{:?}",
  146. self.raw.data.as_ptr(),
  147. self.generation
  148. ))?;
  149. #[cfg(not(any(debug_assertions, feature = "check_generation")))]
  150. f.write_fmt(format_args!("{:?}", self.raw.data.as_ptr()))?;
  151. Ok(())
  152. }
  153. }
  154. impl<T: 'static> GenerationalBox<T> {
  155. #[inline(always)]
  156. fn validate(&self) -> bool {
  157. #[cfg(any(debug_assertions, feature = "check_generation"))]
  158. {
  159. self.raw.generation.get() == self.generation
  160. }
  161. #[cfg(not(any(debug_assertions, feature = "check_generation")))]
  162. {
  163. true
  164. }
  165. }
  166. pub fn try_read(&self) -> Option<Ref<'_, T>> {
  167. self.validate()
  168. .then(|| {
  169. Ref::filter_map(self.raw.data.borrow(), |any| {
  170. any.as_ref()?.downcast_ref::<T>()
  171. })
  172. .ok()
  173. })
  174. .flatten()
  175. }
  176. pub fn read(&self) -> Ref<'_, T> {
  177. self.try_read().unwrap()
  178. }
  179. pub fn try_write(&self) -> Option<RefMut<'_, T>> {
  180. self.validate()
  181. .then(|| {
  182. RefMut::filter_map(self.raw.data.borrow_mut(), |any| {
  183. any.as_mut()?.downcast_mut::<T>()
  184. })
  185. .ok()
  186. })
  187. .flatten()
  188. }
  189. pub fn write(&self) -> RefMut<'_, T> {
  190. self.try_write().unwrap()
  191. }
  192. pub fn set(&self, value: T) {
  193. self.validate().then(|| {
  194. *self.raw.data.borrow_mut() = Some(Box::new(value));
  195. });
  196. }
  197. pub fn ptr_eq(&self, other: &Self) -> bool {
  198. #[cfg(any(debug_assertions, feature = "check_generation"))]
  199. {
  200. self.raw.data.as_ptr() == other.raw.data.as_ptr() && self.generation == other.generation
  201. }
  202. #[cfg(not(any(debug_assertions, feature = "check_generation")))]
  203. {
  204. self.raw.data.as_ptr() == other.raw.data.as_ptr()
  205. }
  206. }
  207. }
  208. impl<T> Copy for GenerationalBox<T> {}
  209. impl<T> Clone for GenerationalBox<T> {
  210. fn clone(&self) -> Self {
  211. *self
  212. }
  213. }
  214. #[derive(Clone, Copy)]
  215. struct MemoryLocation {
  216. data: &'static RefCell<Option<Box<dyn std::any::Any>>>,
  217. #[cfg(any(debug_assertions, feature = "check_generation"))]
  218. generation: &'static Cell<u32>,
  219. }
  220. impl MemoryLocation {
  221. #[allow(unused)]
  222. fn drop(&self) {
  223. let old = self.data.borrow_mut().take();
  224. #[cfg(any(debug_assertions, feature = "check_generation"))]
  225. if old.is_some() {
  226. let new_generation = self.generation.get() + 1;
  227. self.generation.set(new_generation);
  228. }
  229. }
  230. fn replace<T: 'static>(&mut self, value: T) -> GenerationalBox<T> {
  231. let mut inner_mut = self.data.borrow_mut();
  232. let raw = Box::new(value);
  233. let old = inner_mut.replace(raw);
  234. assert!(old.is_none());
  235. GenerationalBox {
  236. raw: *self,
  237. #[cfg(any(debug_assertions, feature = "check_generation"))]
  238. generation: self.generation.get(),
  239. _marker: PhantomData,
  240. }
  241. }
  242. }
  243. /// Handles recycling generational boxes that have been dropped. Your application should have one store or one store per thread.
  244. #[derive(Clone)]
  245. pub struct Store {
  246. bump: &'static Bump,
  247. recycled: Rc<RefCell<Vec<MemoryLocation>>>,
  248. }
  249. impl Default for Store {
  250. fn default() -> Self {
  251. Self {
  252. bump: Box::leak(Box::new(Bump::new())),
  253. recycled: Default::default(),
  254. }
  255. }
  256. }
  257. impl Store {
  258. fn recycle(&self, location: MemoryLocation) {
  259. location.drop();
  260. self.recycled.borrow_mut().push(location);
  261. }
  262. fn claim(&self) -> MemoryLocation {
  263. if let Some(location) = self.recycled.borrow_mut().pop() {
  264. location
  265. } else {
  266. let data: &'static RefCell<_> = self.bump.alloc(RefCell::new(None));
  267. MemoryLocation {
  268. data,
  269. #[cfg(any(debug_assertions, feature = "check_generation"))]
  270. generation: self.bump.alloc(Cell::new(0)),
  271. }
  272. }
  273. }
  274. pub fn owner(&self) -> Owner {
  275. Owner {
  276. store: self.clone(),
  277. owned: Default::default(),
  278. }
  279. }
  280. }
  281. /// Owner: Handles dropping generational boxes. The owner acts like a runtime lifetime guard. Any states that you create with an owner will be dropped when that owner is dropped.
  282. pub struct Owner {
  283. store: Store,
  284. owned: Rc<RefCell<Vec<MemoryLocation>>>,
  285. }
  286. impl Owner {
  287. pub fn insert<T: 'static>(&self, value: T) -> GenerationalBox<T> {
  288. let mut location = self.store.claim();
  289. let key = location.replace(value);
  290. self.owned.borrow_mut().push(location);
  291. key
  292. }
  293. /// Creates an invalid handle. This is useful for creating a handle that will be filled in later. If you use this before the value is filled in, you will get may get a panic or an out of date value.
  294. pub fn invalid<T: 'static>(&self) -> GenerationalBox<T> {
  295. let location = self.store.claim();
  296. GenerationalBox {
  297. raw: location,
  298. #[cfg(any(debug_assertions, feature = "check_generation"))]
  299. generation: location.generation.get(),
  300. _marker: PhantomData,
  301. }
  302. }
  303. }
  304. impl Drop for Owner {
  305. fn drop(&mut self) {
  306. for location in self.owned.borrow().iter() {
  307. self.store.recycle(*location)
  308. }
  309. }
  310. }