lib.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  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. num::NonZeroU64,
  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 entry;
  16. mod error;
  17. mod references;
  18. mod sync;
  19. mod unsync;
  20. /// The type erased id of a generational box.
  21. #[derive(Clone, Copy, PartialEq, Eq, Hash)]
  22. pub struct GenerationalBoxId {
  23. data_ptr: *const (),
  24. generation: NonZeroU64,
  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. f.write_fmt(format_args!("{:?}@{:?}", self.data_ptr, self.generation))?;
  32. Ok(())
  33. }
  34. }
  35. /// The core Copy state type. The generational box will be dropped when the [Owner] is dropped.
  36. pub struct GenerationalBox<T, S: 'static = UnsyncStorage> {
  37. raw: GenerationalPointer<S>,
  38. _marker: PhantomData<T>,
  39. }
  40. impl<T, S: AnyStorage> Debug for GenerationalBox<T, S> {
  41. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  42. self.raw.fmt(f)
  43. }
  44. }
  45. impl<T, S: Storage<T>> GenerationalBox<T, S> {
  46. /// Create a new generational box by leaking a value into the storage. This is useful for creating
  47. /// a box that needs to be manually dropped with no owners.
  48. #[track_caller]
  49. pub fn leak(value: T, location: &'static std::panic::Location<'static>) -> Self {
  50. let location = S::new(value, location);
  51. Self {
  52. raw: location,
  53. _marker: PhantomData,
  54. }
  55. }
  56. /// Create a new reference counted generational box by leaking a value into the storage. This is useful for creating
  57. /// a box that needs to be manually dropped with no owners.
  58. #[track_caller]
  59. pub fn leak_rc(value: T, location: &'static std::panic::Location<'static>) -> Self {
  60. let location = S::new_rc(value, location);
  61. Self {
  62. raw: location,
  63. _marker: PhantomData,
  64. }
  65. }
  66. /// Get the raw pointer to the value.
  67. pub fn raw_ptr(&self) -> *const () {
  68. self.raw.storage.data_ptr()
  69. }
  70. /// Get the id of the generational box.
  71. pub fn id(&self) -> GenerationalBoxId {
  72. self.raw.id()
  73. }
  74. /// Try to read the value. Returns an error if the value is no longer valid.
  75. #[track_caller]
  76. pub fn try_read(&self) -> Result<S::Ref<'static, T>, BorrowError> {
  77. self.raw.try_read()
  78. }
  79. /// Read the value. Panics if the value is no longer valid.
  80. #[track_caller]
  81. pub fn read(&self) -> S::Ref<'static, T> {
  82. self.try_read().unwrap()
  83. }
  84. /// Try to write the value. Returns None if the value is no longer valid.
  85. #[track_caller]
  86. pub fn try_write(&self) -> Result<S::Mut<'static, T>, BorrowMutError> {
  87. self.raw.try_write()
  88. }
  89. /// Write the value. Panics if the value is no longer valid.
  90. #[track_caller]
  91. pub fn write(&self) -> S::Mut<'static, T> {
  92. self.try_write().unwrap()
  93. }
  94. /// Set the value. Panics if the value is no longer valid.
  95. #[track_caller]
  96. pub fn set(&self, value: T)
  97. where
  98. T: 'static,
  99. {
  100. *self.write() = value;
  101. }
  102. /// Returns true if the pointer is equal to the other pointer.
  103. pub fn ptr_eq(&self, other: &Self) -> bool {
  104. self.raw == other.raw
  105. }
  106. /// Drop the value out of the generational box and invalidate the generational box.
  107. pub fn manually_drop(&self)
  108. where
  109. T: 'static,
  110. {
  111. self.raw.recycle();
  112. }
  113. /// Try to get the location the generational box was created at. In release mode this will always return None.
  114. pub fn created_at(&self) -> Option<&'static std::panic::Location<'static>> {
  115. self.raw.location.created_at()
  116. }
  117. /// Get a reference to the value
  118. #[track_caller]
  119. pub fn leak_reference(&self) -> BorrowResult<GenerationalBox<T, S>> {
  120. Ok(Self {
  121. raw: S::new_reference(self.raw)?,
  122. _marker: std::marker::PhantomData,
  123. })
  124. }
  125. /// Change this box to point to another generational box
  126. pub fn point_to(&mut self, other: GenerationalBox<T, S>) -> BorrowResult {
  127. S::change_reference(self.raw, other.raw)
  128. }
  129. }
  130. impl<T, S> Copy for GenerationalBox<T, S> {}
  131. impl<T, S> Clone for GenerationalBox<T, S> {
  132. fn clone(&self) -> Self {
  133. *self
  134. }
  135. }
  136. /// A trait for a storage backing type. (RefCell, RwLock, etc.)
  137. pub trait Storage<Data = ()>: AnyStorage + 'static {
  138. /// Try to read the value. Returns None if the value is no longer valid.
  139. fn try_read(pointer: GenerationalPointer<Self>) -> BorrowResult<Self::Ref<'static, Data>>;
  140. /// Try to write the value. Returns None if the value is no longer valid.
  141. fn try_write(pointer: GenerationalPointer<Self>) -> BorrowMutResult<Self::Mut<'static, Data>>;
  142. /// Create a new memory location. This will either create a new memory location or recycle an old one.
  143. fn new(
  144. value: Data,
  145. caller: &'static std::panic::Location<'static>,
  146. ) -> GenerationalPointer<Self>;
  147. /// Create a new reference counted memory location. This will either create a new memory location or recycle an old one.
  148. fn new_rc(
  149. value: Data,
  150. caller: &'static std::panic::Location<'static>,
  151. ) -> GenerationalPointer<Self>;
  152. /// Reference another location if the location is valid
  153. ///
  154. /// This method may return an error if the other box is no longer valid or it is already borrowed mutably.
  155. fn new_reference(inner: GenerationalPointer<Self>) -> BorrowResult<GenerationalPointer<Self>>;
  156. /// Change the reference a signal is pointing to
  157. ///
  158. /// This method may return an error if the other box is no longer valid or it is already borrowed mutably.
  159. fn change_reference(
  160. pointer: GenerationalPointer<Self>,
  161. rc_pointer: GenerationalPointer<Self>,
  162. ) -> BorrowResult;
  163. }
  164. /// A trait for any storage backing type.
  165. pub trait AnyStorage: Default + 'static {
  166. /// The reference this storage type returns.
  167. type Ref<'a, T: ?Sized + 'static>: Deref<Target = T>;
  168. /// The mutable reference this storage type returns.
  169. type Mut<'a, T: ?Sized + 'static>: DerefMut<Target = T>;
  170. /// Downcast a reference in a Ref to a more specific lifetime
  171. ///
  172. /// This function enforces the variance of the lifetime parameter `'a` in Ref. Rust will typically infer this cast with a concrete type, but it cannot with a generic type.
  173. fn downcast_lifetime_ref<'a: 'b, 'b, T: ?Sized + 'static>(
  174. ref_: Self::Ref<'a, T>,
  175. ) -> Self::Ref<'b, T>;
  176. /// Downcast a mutable reference in a RefMut to a more specific lifetime
  177. ///
  178. /// This function enforces the variance of the lifetime parameter `'a` in Mut. Rust will typically infer this cast with a concrete type, but it cannot with a generic type.
  179. fn downcast_lifetime_mut<'a: 'b, 'b, T: ?Sized + 'static>(
  180. mut_: Self::Mut<'a, T>,
  181. ) -> Self::Mut<'b, T>;
  182. /// Try to map the mutable ref.
  183. fn try_map_mut<T: ?Sized + 'static, U: ?Sized + 'static>(
  184. mut_ref: Self::Mut<'_, T>,
  185. f: impl FnOnce(&mut T) -> Option<&mut U>,
  186. ) -> Option<Self::Mut<'_, U>>;
  187. /// Map the mutable ref.
  188. fn map_mut<T: ?Sized + 'static, U: ?Sized + 'static>(
  189. mut_ref: Self::Mut<'_, T>,
  190. f: impl FnOnce(&mut T) -> &mut U,
  191. ) -> Self::Mut<'_, U> {
  192. Self::try_map_mut(mut_ref, |v| Some(f(v))).unwrap()
  193. }
  194. /// Try to map the ref.
  195. fn try_map<T: ?Sized, U: ?Sized + 'static>(
  196. ref_: Self::Ref<'_, T>,
  197. f: impl FnOnce(&T) -> Option<&U>,
  198. ) -> Option<Self::Ref<'_, U>>;
  199. /// Map the ref.
  200. fn map<T: ?Sized, U: ?Sized + 'static>(
  201. ref_: Self::Ref<'_, T>,
  202. f: impl FnOnce(&T) -> &U,
  203. ) -> Self::Ref<'_, U> {
  204. Self::try_map(ref_, |v| Some(f(v))).unwrap()
  205. }
  206. /// Get the data pointer. No guarantees are made about the data pointer. It should only be used for debugging.
  207. fn data_ptr(&self) -> *const ();
  208. /// Recycle a memory location. This will drop the memory location and return it to the runtime.
  209. fn recycle(location: GenerationalPointer<Self>);
  210. /// Create a new owner. The owner will be responsible for dropping all of the generational boxes that it creates.
  211. fn owner() -> Owner<Self> {
  212. Owner(Arc::new(Mutex::new(OwnerInner {
  213. owned: Default::default(),
  214. })))
  215. }
  216. }
  217. #[derive(Debug, Clone, Copy)]
  218. pub(crate) struct GenerationalLocation {
  219. /// The generation this location is associated with. Using the location after this generation is invalidated will return errors.
  220. generation: NonZeroU64,
  221. #[cfg(any(debug_assertions, feature = "debug_ownership"))]
  222. created_at: &'static std::panic::Location<'static>,
  223. }
  224. impl GenerationalLocation {
  225. pub(crate) fn created_at(&self) -> Option<&'static std::panic::Location<'static>> {
  226. #[cfg(debug_assertions)]
  227. {
  228. Some(self.created_at)
  229. }
  230. #[cfg(not(debug_assertions))]
  231. {
  232. None
  233. }
  234. }
  235. }
  236. /// A pointer to a specific generational box and generation in that box.
  237. pub struct GenerationalPointer<S: 'static = UnsyncStorage> {
  238. /// The storage that is backing this location
  239. storage: &'static S,
  240. /// The location of the data
  241. location: GenerationalLocation,
  242. }
  243. impl<S: AnyStorage + 'static> PartialEq for GenerationalPointer<S> {
  244. fn eq(&self, other: &Self) -> bool {
  245. self.storage.data_ptr() == other.storage.data_ptr()
  246. && self.location.generation == other.location.generation
  247. }
  248. }
  249. impl<S: AnyStorage + 'static> Debug for GenerationalPointer<S> {
  250. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  251. f.write_fmt(format_args!(
  252. "{:?}@{:?}",
  253. self.storage.data_ptr(),
  254. self.location.generation
  255. ))
  256. }
  257. }
  258. impl<S: 'static> Clone for GenerationalPointer<S> {
  259. fn clone(&self) -> Self {
  260. *self
  261. }
  262. }
  263. impl<S: 'static> Copy for GenerationalPointer<S> {}
  264. impl<S> GenerationalPointer<S> {
  265. #[track_caller]
  266. fn try_read<T>(self) -> Result<S::Ref<'static, T>, BorrowError>
  267. where
  268. S: Storage<T>,
  269. {
  270. S::try_read(self)
  271. }
  272. #[track_caller]
  273. fn try_write<T>(self) -> Result<S::Mut<'static, T>, BorrowMutError>
  274. where
  275. S: Storage<T>,
  276. {
  277. S::try_write(self)
  278. }
  279. fn recycle(self)
  280. where
  281. S: AnyStorage,
  282. {
  283. S::recycle(self);
  284. }
  285. fn id(&self) -> GenerationalBoxId
  286. where
  287. S: AnyStorage,
  288. {
  289. GenerationalBoxId {
  290. data_ptr: self.storage.data_ptr(),
  291. generation: self.location.generation,
  292. }
  293. }
  294. }
  295. struct OwnerInner<S: AnyStorage + 'static> {
  296. owned: Vec<GenerationalPointer<S>>,
  297. }
  298. impl<S: AnyStorage> Drop for OwnerInner<S> {
  299. fn drop(&mut self) {
  300. for location in self.owned.drain(..) {
  301. location.recycle();
  302. }
  303. }
  304. }
  305. /// 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.
  306. pub struct Owner<S: AnyStorage + 'static = UnsyncStorage>(Arc<Mutex<OwnerInner<S>>>);
  307. impl<S: AnyStorage> Default for Owner<S> {
  308. fn default() -> Self {
  309. S::owner()
  310. }
  311. }
  312. impl<S: AnyStorage> Clone for Owner<S> {
  313. fn clone(&self) -> Self {
  314. Self(self.0.clone())
  315. }
  316. }
  317. impl<S: AnyStorage> Owner<S> {
  318. /// Insert a value into the store. The value will be dropped when the owner is dropped.
  319. #[track_caller]
  320. pub fn insert<T: 'static>(&self, value: T) -> GenerationalBox<T, S>
  321. where
  322. S: Storage<T>,
  323. {
  324. self.insert_with_caller(value, std::panic::Location::caller())
  325. }
  326. /// Create a new reference counted box. The box will be dropped when all references are dropped.
  327. #[track_caller]
  328. pub fn insert_rc<T: 'static>(&self, value: T) -> GenerationalBox<T, S>
  329. where
  330. S: Storage<T>,
  331. {
  332. self.insert_rc_with_caller(value, std::panic::Location::caller())
  333. }
  334. /// 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.
  335. pub fn insert_rc_with_caller<T: 'static>(
  336. &self,
  337. value: T,
  338. caller: &'static std::panic::Location<'static>,
  339. ) -> GenerationalBox<T, S>
  340. where
  341. S: Storage<T>,
  342. {
  343. let location = S::new_rc(value, caller);
  344. self.0.lock().owned.push(location);
  345. GenerationalBox {
  346. raw: location,
  347. _marker: std::marker::PhantomData,
  348. }
  349. }
  350. /// 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.
  351. pub fn insert_with_caller<T: 'static>(
  352. &self,
  353. value: T,
  354. caller: &'static std::panic::Location<'static>,
  355. ) -> GenerationalBox<T, S>
  356. where
  357. S: Storage<T>,
  358. {
  359. let location = S::new(value, caller);
  360. self.0.lock().owned.push(location);
  361. GenerationalBox {
  362. raw: location,
  363. _marker: PhantomData,
  364. }
  365. }
  366. /// Create a new reference to an existing box. The reference will be dropped when the owner is dropped.
  367. ///
  368. /// This method may return an error if the other box is no longer valid or it is already borrowed mutably.
  369. #[track_caller]
  370. pub fn insert_reference<T: 'static>(
  371. &self,
  372. other: GenerationalBox<T, S>,
  373. ) -> BorrowResult<GenerationalBox<T, S>>
  374. where
  375. S: Storage<T>,
  376. {
  377. let location = other.leak_reference()?;
  378. self.0.lock().owned.push(location.raw);
  379. Ok(location)
  380. }
  381. }