lib.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. #![doc = include_str!("../README.md")]
  2. #![warn(missing_docs)]
  3. use parking_lot::Mutex;
  4. use std::sync::atomic::AtomicU32;
  5. use std::{
  6. fmt::Debug,
  7. marker::PhantomData,
  8. ops::{Deref, DerefMut},
  9. sync::Arc,
  10. };
  11. pub use error::*;
  12. pub use references::*;
  13. pub use sync::SyncStorage;
  14. pub use unsync::UnsyncStorage;
  15. mod error;
  16. mod references;
  17. mod sync;
  18. mod unsync;
  19. /// The type erased id of a generational box.
  20. #[derive(Clone, Copy, PartialEq, Eq, Hash)]
  21. pub struct GenerationalBoxId {
  22. data_ptr: *const (),
  23. #[cfg(any(debug_assertions, feature = "check_generation"))]
  24. generation: u32,
  25. }
  26. // Safety: GenerationalBoxId is Send and Sync because there is no way to access the pointer.
  27. unsafe impl Send for GenerationalBoxId {}
  28. unsafe impl Sync for GenerationalBoxId {}
  29. impl Debug for GenerationalBoxId {
  30. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  31. #[cfg(any(debug_assertions, feature = "check_generation"))]
  32. f.write_fmt(format_args!("{:?}@{:?}", self.data_ptr, self.generation))?;
  33. #[cfg(not(any(debug_assertions, feature = "check_generation")))]
  34. f.write_fmt(format_args!("{:?}", self.data_ptr))?;
  35. Ok(())
  36. }
  37. }
  38. /// The core Copy state type. The generational box will be dropped when the [Owner] is dropped.
  39. pub struct GenerationalBox<T, S: 'static = UnsyncStorage> {
  40. raw: MemoryLocation<S>,
  41. #[cfg(any(debug_assertions, feature = "check_generation"))]
  42. generation: u32,
  43. #[cfg(any(debug_assertions, feature = "debug_ownership"))]
  44. created_at: &'static std::panic::Location<'static>,
  45. _marker: PhantomData<T>,
  46. }
  47. impl<T: 'static, S: AnyStorage> Debug for GenerationalBox<T, S> {
  48. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  49. #[cfg(any(debug_assertions, feature = "check_generation"))]
  50. f.write_fmt(format_args!(
  51. "{:?}@{:?}",
  52. self.raw.0.data.data_ptr(),
  53. self.generation
  54. ))?;
  55. #[cfg(not(any(debug_assertions, feature = "check_generation")))]
  56. f.write_fmt(format_args!("{:?}", self.raw.0.data.as_ptr()))?;
  57. Ok(())
  58. }
  59. }
  60. impl<T: 'static, S: Storage<T>> GenerationalBox<T, S> {
  61. #[inline(always)]
  62. pub fn validate(&self) -> bool {
  63. #[cfg(any(debug_assertions, feature = "check_generation"))]
  64. {
  65. self.raw
  66. .0
  67. .generation
  68. .load(std::sync::atomic::Ordering::Relaxed)
  69. == self.generation
  70. }
  71. #[cfg(not(any(debug_assertions, feature = "check_generation")))]
  72. {
  73. true
  74. }
  75. }
  76. /// Get the raw pointer to the value.
  77. pub fn raw_ptr(&self) -> *const () {
  78. self.raw.0.data.data_ptr()
  79. }
  80. /// Get the id of the generational box.
  81. pub fn id(&self) -> GenerationalBoxId {
  82. GenerationalBoxId {
  83. data_ptr: self.raw.0.data.data_ptr(),
  84. #[cfg(any(debug_assertions, feature = "check_generation"))]
  85. generation: self.generation,
  86. }
  87. }
  88. /// Try to read the value. Returns None if the value is no longer valid.
  89. #[track_caller]
  90. pub fn try_read(&self) -> Result<S::Ref<T>, BorrowError> {
  91. if !self.validate() {
  92. return Err(BorrowError::Dropped(ValueDroppedError {
  93. #[cfg(any(debug_assertions, feature = "debug_borrows"))]
  94. created_at: self.created_at,
  95. }));
  96. }
  97. let result = self.raw.0.data.try_read(
  98. #[cfg(any(debug_assertions, feature = "debug_ownership"))]
  99. GenerationalRefBorrowInfo {
  100. borrowed_at: std::panic::Location::caller(),
  101. borrowed_from: &self.raw.0.borrow,
  102. created_at: self.created_at,
  103. },
  104. );
  105. if result.is_ok() {
  106. #[cfg(any(debug_assertions, feature = "debug_ownership"))]
  107. self.raw
  108. .0
  109. .borrow
  110. .borrowed_at
  111. .write()
  112. .push(std::panic::Location::caller());
  113. }
  114. result
  115. }
  116. /// Read the value. Panics if the value is no longer valid.
  117. #[track_caller]
  118. pub fn read(&self) -> S::Ref<T> {
  119. self.try_read().unwrap()
  120. }
  121. /// Try to write the value. Returns None if the value is no longer valid.
  122. #[track_caller]
  123. pub fn try_write(&self) -> Result<S::Mut<T>, BorrowMutError> {
  124. if !self.validate() {
  125. return Err(BorrowMutError::Dropped(ValueDroppedError {
  126. #[cfg(any(debug_assertions, feature = "debug_borrows"))]
  127. created_at: self.created_at,
  128. }));
  129. }
  130. let result = self.raw.0.data.try_write(
  131. #[cfg(any(debug_assertions, feature = "debug_ownership"))]
  132. GenerationalRefMutBorrowInfo {
  133. borrowed_from: &self.raw.0.borrow,
  134. created_at: self.created_at,
  135. },
  136. );
  137. if result.is_ok() {
  138. #[cfg(any(debug_assertions, feature = "debug_ownership"))]
  139. {
  140. *self.raw.0.borrow.borrowed_mut_at.write() = Some(std::panic::Location::caller());
  141. }
  142. }
  143. result
  144. }
  145. /// Write the value. Panics if the value is no longer valid.
  146. #[track_caller]
  147. pub fn write(&self) -> S::Mut<T> {
  148. self.try_write().unwrap()
  149. }
  150. /// Set the value. Panics if the value is no longer valid.
  151. pub fn set(&self, value: T) {
  152. self.validate().then(|| {
  153. self.raw.0.data.set(value);
  154. });
  155. }
  156. /// Returns true if the pointer is equal to the other pointer.
  157. pub fn ptr_eq(&self, other: &Self) -> bool {
  158. #[cfg(any(debug_assertions, feature = "check_generation"))]
  159. {
  160. self.raw.0.data.data_ptr() == other.raw.0.data.data_ptr()
  161. && self.generation == other.generation
  162. }
  163. #[cfg(not(any(debug_assertions, feature = "check_generation")))]
  164. {
  165. self.raw.data.as_ptr() == other.raw.data.as_ptr()
  166. }
  167. }
  168. }
  169. impl<T, S: 'static> Copy for GenerationalBox<T, S> {}
  170. impl<T, S> Clone for GenerationalBox<T, S> {
  171. fn clone(&self) -> Self {
  172. *self
  173. }
  174. }
  175. /// A trait for a storage backing type. (RefCell, RwLock, etc.)
  176. pub trait Storage<Data = ()>: AnyStorage + 'static {
  177. /// The reference this storage type returns.
  178. type Ref<T: ?Sized + 'static>: Deref<Target = T>;
  179. /// The mutable reference this storage type returns.
  180. type Mut<T: ?Sized + 'static>: DerefMut<Target = T>;
  181. /// Try to map the mutable ref.
  182. fn try_map_mut<T, U: ?Sized + 'static>(
  183. mut_ref: Self::Mut<T>,
  184. f: impl FnOnce(&mut T) -> Option<&mut U>,
  185. ) -> Option<Self::Mut<U>>;
  186. /// Map the mutable ref.
  187. fn map_mut<T, U: ?Sized + 'static>(
  188. mut_ref: Self::Mut<T>,
  189. f: impl FnOnce(&mut T) -> &mut U,
  190. ) -> Self::Mut<U> {
  191. Self::try_map_mut(mut_ref, |v| Some(f(v))).unwrap()
  192. }
  193. /// Try to map the ref.
  194. fn try_map<T, U: ?Sized + 'static>(
  195. ref_: Self::Ref<T>,
  196. f: impl FnOnce(&T) -> Option<&U>,
  197. ) -> Option<Self::Ref<U>>;
  198. /// Map the ref.
  199. fn map<T, U: ?Sized + 'static>(ref_: Self::Ref<T>, f: impl FnOnce(&T) -> &U) -> Self::Ref<U> {
  200. Self::try_map(ref_, |v| Some(f(v))).unwrap()
  201. }
  202. /// Try to read the value. Returns None if the value is no longer valid.
  203. fn try_read(
  204. &'static self,
  205. #[cfg(any(debug_assertions, feature = "debug_ownership"))] at: GenerationalRefBorrowInfo,
  206. ) -> Result<Self::Ref<Data>, BorrowError>;
  207. /// Try to write the value. Returns None if the value is no longer valid.
  208. fn try_write(
  209. &'static self,
  210. #[cfg(any(debug_assertions, feature = "debug_ownership"))] at: GenerationalRefMutBorrowInfo,
  211. ) -> Result<Self::Mut<Data>, BorrowMutError>;
  212. /// Set the value
  213. fn set(&'static self, value: Data);
  214. }
  215. /// A trait for any storage backing type.
  216. pub trait AnyStorage: Default {
  217. /// Get the data pointer. No guarantees are made about the data pointer. It should only be used for debugging.
  218. fn data_ptr(&self) -> *const ();
  219. /// Take the value out of the storage. This will return true if the value was taken.
  220. fn take(&self) -> bool;
  221. /// Recycle a memory location. This will drop the memory location and return it to the runtime.
  222. fn recycle(location: &MemoryLocation<Self>);
  223. /// Claim a new memory location. This will either create a new memory location or recycle an old one.
  224. fn claim() -> MemoryLocation<Self>;
  225. /// Create a new owner. The owner will be responsible for dropping all of the generational boxes that it creates.
  226. fn owner() -> Owner<Self> {
  227. Owner {
  228. owned: Default::default(),
  229. phantom: PhantomData,
  230. }
  231. }
  232. }
  233. /// A dynamic memory location that can be used in a generational box.
  234. pub struct MemoryLocation<S: 'static = UnsyncStorage>(&'static MemoryLocationInner<S>);
  235. impl<S: 'static> Clone for MemoryLocation<S> {
  236. fn clone(&self) -> Self {
  237. *self
  238. }
  239. }
  240. impl<S: 'static> Copy for MemoryLocation<S> {}
  241. #[cfg(any(debug_assertions, feature = "debug_borrows"))]
  242. #[derive(Debug, Default)]
  243. struct MemoryLocationBorrowInfo {
  244. pub(crate) borrowed_at: parking_lot::RwLock<Vec<&'static std::panic::Location<'static>>>,
  245. pub(crate) borrowed_mut_at: parking_lot::RwLock<Option<&'static std::panic::Location<'static>>>,
  246. }
  247. #[cfg(any(debug_assertions, feature = "debug_ownership"))]
  248. impl MemoryLocationBorrowInfo {
  249. fn borrow_mut_error(&self) -> BorrowMutError {
  250. if let Some(borrowed_mut_at) = self.borrowed_mut_at.read().as_ref() {
  251. BorrowMutError::AlreadyBorrowedMut(crate::error::AlreadyBorrowedMutError {
  252. #[cfg(any(debug_assertions, feature = "debug_borrows"))]
  253. borrowed_mut_at,
  254. })
  255. } else {
  256. BorrowMutError::AlreadyBorrowed(crate::error::AlreadyBorrowedError {
  257. #[cfg(any(debug_assertions, feature = "debug_borrows"))]
  258. borrowed_at: self.borrowed_at.read().clone(),
  259. })
  260. }
  261. }
  262. fn borrow_error(&self) -> BorrowError {
  263. BorrowError::AlreadyBorrowedMut(crate::error::AlreadyBorrowedMutError {
  264. #[cfg(any(debug_assertions, feature = "debug_ownership"))]
  265. borrowed_mut_at: self.borrowed_mut_at.read().unwrap(),
  266. })
  267. }
  268. }
  269. struct MemoryLocationInner<S = UnsyncStorage> {
  270. data: S,
  271. #[cfg(any(debug_assertions, feature = "check_generation"))]
  272. generation: AtomicU32,
  273. #[cfg(any(debug_assertions, feature = "debug_borrows"))]
  274. borrow: MemoryLocationBorrowInfo,
  275. }
  276. impl<S> MemoryLocation<S> {
  277. #[allow(unused)]
  278. fn drop(&self)
  279. where
  280. S: AnyStorage,
  281. {
  282. let old = self.0.data.take();
  283. #[cfg(any(debug_assertions, feature = "check_generation"))]
  284. if old {
  285. let new_generation = self.0.generation.load(std::sync::atomic::Ordering::Relaxed) + 1;
  286. self.0
  287. .generation
  288. .store(new_generation, std::sync::atomic::Ordering::Relaxed);
  289. }
  290. }
  291. fn replace_with_caller<T: 'static>(
  292. &mut self,
  293. value: T,
  294. #[cfg(any(debug_assertions, feature = "debug_ownership"))]
  295. caller: &'static std::panic::Location<'static>,
  296. ) -> GenerationalBox<T, S>
  297. where
  298. S: Storage<T>,
  299. {
  300. self.0.data.set(value);
  301. GenerationalBox {
  302. raw: *self,
  303. #[cfg(any(debug_assertions, feature = "check_generation"))]
  304. generation: self.0.generation.load(std::sync::atomic::Ordering::Relaxed),
  305. #[cfg(any(debug_assertions, feature = "debug_ownership"))]
  306. created_at: caller,
  307. _marker: PhantomData,
  308. }
  309. }
  310. }
  311. /// 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.
  312. pub struct Owner<S: AnyStorage + 'static = UnsyncStorage> {
  313. owned: Arc<Mutex<Vec<MemoryLocation<S>>>>,
  314. phantom: PhantomData<S>,
  315. }
  316. impl<S: AnyStorage> Owner<S> {
  317. /// Insert a value into the store. The value will be dropped when the owner is dropped.
  318. #[track_caller]
  319. pub fn insert<T: 'static>(&self, value: T) -> GenerationalBox<T, S>
  320. where
  321. S: Storage<T>,
  322. {
  323. self.insert_with_caller(
  324. value,
  325. #[cfg(any(debug_assertions, feature = "debug_ownership"))]
  326. std::panic::Location::caller(),
  327. )
  328. }
  329. /// Insert a value into the store with a specific location blamed for creating the value. The value will be dropped when the owner is dropped.
  330. pub fn insert_with_caller<T: 'static>(
  331. &self,
  332. value: T,
  333. #[cfg(any(debug_assertions, feature = "debug_ownership"))]
  334. caller: &'static std::panic::Location<'static>,
  335. ) -> GenerationalBox<T, S>
  336. where
  337. S: Storage<T>,
  338. {
  339. let mut location = S::claim();
  340. let key = location.replace_with_caller(
  341. value,
  342. #[cfg(any(debug_assertions, feature = "debug_borrows"))]
  343. caller,
  344. );
  345. self.owned.lock().push(location);
  346. key
  347. }
  348. /// 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.
  349. pub fn invalid<T: 'static>(&self) -> GenerationalBox<T, S> {
  350. let location = S::claim();
  351. let generational_box = GenerationalBox {
  352. raw: location,
  353. #[cfg(any(debug_assertions, feature = "check_generation"))]
  354. generation: location
  355. .0
  356. .generation
  357. .load(std::sync::atomic::Ordering::Relaxed),
  358. #[cfg(any(debug_assertions, feature = "debug_ownership"))]
  359. created_at: std::panic::Location::caller(),
  360. _marker: PhantomData,
  361. };
  362. self.owned.lock().push(location);
  363. generational_box
  364. }
  365. }
  366. impl<S: AnyStorage> Drop for Owner<S> {
  367. fn drop(&mut self) {
  368. for location in self.owned.lock().iter() {
  369. S::recycle(location)
  370. }
  371. }
  372. }