lib.rs 10.0 KB

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