1
0

lib.rs 15 KB

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