|
@@ -14,6 +14,7 @@ pub use references::*;
|
|
pub use sync::SyncStorage;
|
|
pub use sync::SyncStorage;
|
|
pub use unsync::UnsyncStorage;
|
|
pub use unsync::UnsyncStorage;
|
|
|
|
|
|
|
|
+mod entry;
|
|
mod error;
|
|
mod error;
|
|
mod references;
|
|
mod references;
|
|
mod sync;
|
|
mod sync;
|
|
@@ -23,8 +24,7 @@ mod unsync;
|
|
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
|
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
|
pub struct GenerationalBoxId {
|
|
pub struct GenerationalBoxId {
|
|
data_ptr: *const (),
|
|
data_ptr: *const (),
|
|
- #[cfg(any(debug_assertions, feature = "check_generation"))]
|
|
|
|
- generation: u32,
|
|
|
|
|
|
+ generation: u64,
|
|
}
|
|
}
|
|
|
|
|
|
// Safety: GenerationalBoxId is Send and Sync because there is no way to access the pointer.
|
|
// Safety: GenerationalBoxId is Send and Sync because there is no way to access the pointer.
|
|
@@ -33,35 +33,20 @@ unsafe impl Sync for GenerationalBoxId {}
|
|
|
|
|
|
impl Debug for GenerationalBoxId {
|
|
impl Debug for GenerationalBoxId {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
- #[cfg(any(debug_assertions, feature = "check_generation"))]
|
|
|
|
f.write_fmt(format_args!("{:?}@{:?}", self.data_ptr, self.generation))?;
|
|
f.write_fmt(format_args!("{:?}@{:?}", self.data_ptr, self.generation))?;
|
|
- #[cfg(not(any(debug_assertions, feature = "check_generation")))]
|
|
|
|
- f.write_fmt(format_args!("{:?}", self.data_ptr))?;
|
|
|
|
Ok(())
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// The core Copy state type. The generational box will be dropped when the [Owner] is dropped.
|
|
/// The core Copy state type. The generational box will be dropped when the [Owner] is dropped.
|
|
pub struct GenerationalBox<T, S: 'static = UnsyncStorage> {
|
|
pub struct GenerationalBox<T, S: 'static = UnsyncStorage> {
|
|
- raw: MemoryLocation<S>,
|
|
|
|
- #[cfg(any(debug_assertions, feature = "check_generation"))]
|
|
|
|
- generation: u32,
|
|
|
|
- #[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
|
|
- created_at: &'static std::panic::Location<'static>,
|
|
|
|
|
|
+ raw: GenerationalPointer<S>,
|
|
_marker: PhantomData<T>,
|
|
_marker: PhantomData<T>,
|
|
}
|
|
}
|
|
|
|
|
|
impl<T, S: AnyStorage> Debug for GenerationalBox<T, S> {
|
|
impl<T, S: AnyStorage> Debug for GenerationalBox<T, S> {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
- #[cfg(any(debug_assertions, feature = "check_generation"))]
|
|
|
|
- f.write_fmt(format_args!(
|
|
|
|
- "{:?}@{:?}",
|
|
|
|
- self.raw.0.data.data_ptr(),
|
|
|
|
- self.generation
|
|
|
|
- ))?;
|
|
|
|
- #[cfg(not(any(debug_assertions, feature = "check_generation")))]
|
|
|
|
- f.write_fmt(format_args!("{:?}", self.raw.0.data.data_ptr()))?;
|
|
|
|
- Ok(())
|
|
|
|
|
|
+ self.raw.fmt(f)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -70,73 +55,28 @@ impl<T, S: Storage<T>> GenerationalBox<T, S> {
|
|
/// a box that needs to be manually dropped with no owners.
|
|
/// a box that needs to be manually dropped with no owners.
|
|
#[track_caller]
|
|
#[track_caller]
|
|
pub fn leak(value: T) -> Self {
|
|
pub fn leak(value: T) -> Self {
|
|
- let mut location = S::claim();
|
|
|
|
- location.replace_with_caller(
|
|
|
|
- value,
|
|
|
|
- #[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
|
|
- std::panic::Location::caller(),
|
|
|
|
- )
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- #[inline(always)]
|
|
|
|
- pub(crate) fn validate(&self) -> bool {
|
|
|
|
- #[cfg(any(debug_assertions, feature = "check_generation"))]
|
|
|
|
- {
|
|
|
|
- self.raw
|
|
|
|
- .0
|
|
|
|
- .generation
|
|
|
|
- .load(std::sync::atomic::Ordering::Relaxed)
|
|
|
|
- == self.generation
|
|
|
|
- }
|
|
|
|
- #[cfg(not(any(debug_assertions, feature = "check_generation")))]
|
|
|
|
- {
|
|
|
|
- true
|
|
|
|
|
|
+ let location = S::claim(std::panic::Location::caller());
|
|
|
|
+ location.set(value);
|
|
|
|
+ Self {
|
|
|
|
+ raw: location,
|
|
|
|
+ _marker: PhantomData,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// Get the raw pointer to the value.
|
|
/// Get the raw pointer to the value.
|
|
pub fn raw_ptr(&self) -> *const () {
|
|
pub fn raw_ptr(&self) -> *const () {
|
|
- self.raw.0.data.data_ptr()
|
|
|
|
|
|
+ self.raw.storage.data_ptr()
|
|
}
|
|
}
|
|
|
|
|
|
/// Get the id of the generational box.
|
|
/// Get the id of the generational box.
|
|
pub fn id(&self) -> GenerationalBoxId {
|
|
pub fn id(&self) -> GenerationalBoxId {
|
|
- GenerationalBoxId {
|
|
|
|
- data_ptr: self.raw.0.data.data_ptr(),
|
|
|
|
- #[cfg(any(debug_assertions, feature = "check_generation"))]
|
|
|
|
- generation: self.generation,
|
|
|
|
- }
|
|
|
|
|
|
+ self.raw.id()
|
|
}
|
|
}
|
|
|
|
|
|
- /// Try to read the value. Returns None if the value is no longer valid.
|
|
|
|
|
|
+ /// Try to read the value. Returns an error if the value is no longer valid.
|
|
#[track_caller]
|
|
#[track_caller]
|
|
pub fn try_read(&self) -> Result<S::Ref<'static, T>, BorrowError> {
|
|
pub fn try_read(&self) -> Result<S::Ref<'static, T>, BorrowError> {
|
|
- if !self.validate() {
|
|
|
|
- return Err(BorrowError::Dropped(ValueDroppedError {
|
|
|
|
- #[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
|
|
|
- created_at: self.created_at,
|
|
|
|
- }));
|
|
|
|
- }
|
|
|
|
- let result = self.raw.0.data.try_read(
|
|
|
|
- #[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
|
|
- GenerationalRefBorrowInfo {
|
|
|
|
- borrowed_at: std::panic::Location::caller(),
|
|
|
|
- borrowed_from: &self.raw.0.borrow,
|
|
|
|
- created_at: self.created_at,
|
|
|
|
- },
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- if result.is_ok() {
|
|
|
|
- #[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
|
|
- self.raw
|
|
|
|
- .0
|
|
|
|
- .borrow
|
|
|
|
- .borrowed_at
|
|
|
|
- .write()
|
|
|
|
- .push(std::panic::Location::caller());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- result
|
|
|
|
|
|
+ self.raw.try_read()
|
|
}
|
|
}
|
|
|
|
|
|
/// Read the value. Panics if the value is no longer valid.
|
|
/// Read the value. Panics if the value is no longer valid.
|
|
@@ -148,28 +88,7 @@ impl<T, S: Storage<T>> GenerationalBox<T, S> {
|
|
/// Try to write the value. Returns None if the value is no longer valid.
|
|
/// Try to write the value. Returns None if the value is no longer valid.
|
|
#[track_caller]
|
|
#[track_caller]
|
|
pub fn try_write(&self) -> Result<S::Mut<'static, T>, BorrowMutError> {
|
|
pub fn try_write(&self) -> Result<S::Mut<'static, T>, BorrowMutError> {
|
|
- if !self.validate() {
|
|
|
|
- return Err(BorrowMutError::Dropped(ValueDroppedError {
|
|
|
|
- #[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
|
|
|
- created_at: self.created_at,
|
|
|
|
- }));
|
|
|
|
- }
|
|
|
|
- let result = self.raw.0.data.try_write(
|
|
|
|
- #[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
|
|
- GenerationalRefMutBorrowInfo {
|
|
|
|
- borrowed_from: &self.raw.0.borrow,
|
|
|
|
- created_at: self.created_at,
|
|
|
|
- },
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- if result.is_ok() {
|
|
|
|
- #[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
|
|
- {
|
|
|
|
- *self.raw.0.borrow.borrowed_mut_at.write() = Some(std::panic::Location::caller());
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- result
|
|
|
|
|
|
+ self.raw.try_write()
|
|
}
|
|
}
|
|
|
|
|
|
/// Write the value. Panics if the value is no longer valid.
|
|
/// Write the value. Panics if the value is no longer valid.
|
|
@@ -180,42 +99,21 @@ impl<T, S: Storage<T>> GenerationalBox<T, S> {
|
|
|
|
|
|
/// Set the value. Panics if the value is no longer valid.
|
|
/// Set the value. Panics if the value is no longer valid.
|
|
pub fn set(&self, value: T) {
|
|
pub fn set(&self, value: T) {
|
|
- self.validate().then(|| {
|
|
|
|
- self.raw.0.data.set(value);
|
|
|
|
- });
|
|
|
|
|
|
+ S::set(self.raw, value);
|
|
}
|
|
}
|
|
|
|
|
|
/// Returns true if the pointer is equal to the other pointer.
|
|
/// Returns true if the pointer is equal to the other pointer.
|
|
pub fn ptr_eq(&self, other: &Self) -> bool {
|
|
pub fn ptr_eq(&self, other: &Self) -> bool {
|
|
- #[cfg(any(debug_assertions, feature = "check_generation"))]
|
|
|
|
- {
|
|
|
|
- self.raw.0.data.data_ptr() == other.raw.0.data.data_ptr()
|
|
|
|
- && self.generation == other.generation
|
|
|
|
- }
|
|
|
|
- #[cfg(not(any(debug_assertions, feature = "check_generation")))]
|
|
|
|
- {
|
|
|
|
- self.raw.0.data.data_ptr() == other.raw.0.data.data_ptr()
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /// Recycle the generationalbox, dropping the value.
|
|
|
|
- pub fn recycle(&self) {
|
|
|
|
- if self.validate() {
|
|
|
|
- <S as AnyStorage>::recycle(&self.raw);
|
|
|
|
- }
|
|
|
|
|
|
+ self.raw == other.raw
|
|
}
|
|
}
|
|
|
|
|
|
/// Drop the value out of the generational box and invalidate the generational box.
|
|
/// Drop the value out of the generational box and invalidate the generational box.
|
|
/// This will return the value if the value was taken.
|
|
/// This will return the value if the value was taken.
|
|
- pub fn manually_drop(&self) -> Option<T> {
|
|
|
|
- if self.validate() {
|
|
|
|
- // TODO: Next breaking release we should change the take method to automatically recycle the box
|
|
|
|
- let value = Storage::take(&self.raw.0.data)?;
|
|
|
|
- <S as AnyStorage>::recycle(&self.raw);
|
|
|
|
- Some(value)
|
|
|
|
- } else {
|
|
|
|
- None
|
|
|
|
- }
|
|
|
|
|
|
+ pub fn manually_drop(&self) -> Option<T>
|
|
|
|
+ where
|
|
|
|
+ T: 'static,
|
|
|
|
+ {
|
|
|
|
+ self.raw.take()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -231,25 +129,20 @@ impl<T, S> Clone for GenerationalBox<T, S> {
|
|
pub trait Storage<Data = ()>: AnyStorage + 'static {
|
|
pub trait Storage<Data = ()>: AnyStorage + 'static {
|
|
/// Try to read the value. Returns None if the value is no longer valid.
|
|
/// Try to read the value. Returns None if the value is no longer valid.
|
|
fn try_read(
|
|
fn try_read(
|
|
- &'static self,
|
|
|
|
- #[cfg(any(debug_assertions, feature = "debug_ownership"))] at: GenerationalRefBorrowInfo,
|
|
|
|
|
|
+ location: GenerationalPointer<Self>,
|
|
) -> Result<Self::Ref<'static, Data>, BorrowError>;
|
|
) -> Result<Self::Ref<'static, Data>, BorrowError>;
|
|
|
|
|
|
/// Try to write the value. Returns None if the value is no longer valid.
|
|
/// Try to write the value. Returns None if the value is no longer valid.
|
|
fn try_write(
|
|
fn try_write(
|
|
- &'static self,
|
|
|
|
- #[cfg(any(debug_assertions, feature = "debug_ownership"))] at: GenerationalRefMutBorrowInfo,
|
|
|
|
|
|
+ location: GenerationalPointer<Self>,
|
|
) -> Result<Self::Mut<'static, Data>, BorrowMutError>;
|
|
) -> Result<Self::Mut<'static, Data>, BorrowMutError>;
|
|
|
|
|
|
- /// Set the value
|
|
|
|
- fn set(&'static self, value: Data);
|
|
|
|
-
|
|
|
|
- /// Take the value out of the storage. This will return the value if the value was taken.
|
|
|
|
- fn take(&'static self) -> Option<Data>;
|
|
|
|
|
|
+ /// Set the value if the location is valid
|
|
|
|
+ fn set(location: GenerationalPointer<Self>, value: Data);
|
|
}
|
|
}
|
|
|
|
|
|
/// A trait for any storage backing type.
|
|
/// A trait for any storage backing type.
|
|
-pub trait AnyStorage: Default {
|
|
|
|
|
|
+pub trait AnyStorage: Default + 'static {
|
|
/// The reference this storage type returns.
|
|
/// The reference this storage type returns.
|
|
type Ref<'a, T: ?Sized + 'static>: Deref<Target = T>;
|
|
type Ref<'a, T: ?Sized + 'static>: Deref<Target = T>;
|
|
/// The mutable reference this storage type returns.
|
|
/// The mutable reference this storage type returns.
|
|
@@ -300,14 +193,11 @@ pub trait AnyStorage: Default {
|
|
/// Get the data pointer. No guarantees are made about the data pointer. It should only be used for debugging.
|
|
/// Get the data pointer. No guarantees are made about the data pointer. It should only be used for debugging.
|
|
fn data_ptr(&self) -> *const ();
|
|
fn data_ptr(&self) -> *const ();
|
|
|
|
|
|
- /// Drop the value from the storage. This will return true if the value was taken.
|
|
|
|
- fn manually_drop(&self) -> bool;
|
|
|
|
-
|
|
|
|
/// Recycle a memory location. This will drop the memory location and return it to the runtime.
|
|
/// Recycle a memory location. This will drop the memory location and return it to the runtime.
|
|
- fn recycle(location: &MemoryLocation<Self>);
|
|
|
|
|
|
+ fn recycle(location: GenerationalPointer<Self>) -> Option<Box<dyn std::any::Any>>;
|
|
|
|
|
|
/// Claim a new memory location. This will either create a new memory location or recycle an old one.
|
|
/// Claim a new memory location. This will either create a new memory location or recycle an old one.
|
|
- fn claim() -> MemoryLocation<Self>;
|
|
|
|
|
|
+ fn claim(caller: &'static std::panic::Location<'static>) -> GenerationalPointer<Self>;
|
|
|
|
|
|
/// Create a new owner. The owner will be responsible for dropping all of the generational boxes that it creates.
|
|
/// Create a new owner. The owner will be responsible for dropping all of the generational boxes that it creates.
|
|
fn owner() -> Owner<Self> {
|
|
fn owner() -> Owner<Self> {
|
|
@@ -317,142 +207,104 @@ pub trait AnyStorage: Default {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-/// A dynamic memory location that can be used in a generational box.
|
|
|
|
-pub struct MemoryLocation<S: 'static = UnsyncStorage>(&'static MemoryLocationInner<S>);
|
|
|
|
-
|
|
|
|
-impl<S: 'static> Clone for MemoryLocation<S> {
|
|
|
|
- fn clone(&self) -> Self {
|
|
|
|
- *self
|
|
|
|
- }
|
|
|
|
|
|
+#[derive(Debug, Clone, Copy)]
|
|
|
|
+pub(crate) struct GenerationalLocation {
|
|
|
|
+ /// The generation this location is associated with. Using the location after this generation is invalidated will return errors.
|
|
|
|
+ generation: u64,
|
|
|
|
+ #[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
|
|
+ created_at: &'static std::panic::Location<'static>,
|
|
}
|
|
}
|
|
|
|
|
|
-impl<S: 'static> Copy for MemoryLocation<S> {}
|
|
|
|
-
|
|
|
|
-#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
|
|
|
-#[derive(Debug, Default)]
|
|
|
|
-struct MemoryLocationBorrowInfo {
|
|
|
|
- pub(crate) borrowed_at: parking_lot::RwLock<Vec<&'static std::panic::Location<'static>>>,
|
|
|
|
- pub(crate) borrowed_mut_at: parking_lot::RwLock<Option<&'static std::panic::Location<'static>>>,
|
|
|
|
|
|
+/// A pointer to a specific generational box and generation in that box.
|
|
|
|
+pub struct GenerationalPointer<S: 'static = UnsyncStorage> {
|
|
|
|
+ /// The storage that is backing this location
|
|
|
|
+ storage: &'static S,
|
|
|
|
+ /// The location of the data
|
|
|
|
+ location: GenerationalLocation,
|
|
}
|
|
}
|
|
|
|
|
|
-#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
|
|
-impl MemoryLocationBorrowInfo {
|
|
|
|
- fn borrow_mut_error(&self) -> BorrowMutError {
|
|
|
|
- if let Some(borrowed_mut_at) = self.borrowed_mut_at.read().as_ref() {
|
|
|
|
- BorrowMutError::AlreadyBorrowedMut(crate::error::AlreadyBorrowedMutError {
|
|
|
|
- #[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
|
|
|
- borrowed_mut_at,
|
|
|
|
- })
|
|
|
|
- } else {
|
|
|
|
- BorrowMutError::AlreadyBorrowed(crate::error::AlreadyBorrowedError {
|
|
|
|
- #[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
|
|
|
- borrowed_at: self.borrowed_at.read().clone(),
|
|
|
|
- })
|
|
|
|
- }
|
|
|
|
|
|
+impl<S: AnyStorage + 'static> PartialEq for GenerationalPointer<S> {
|
|
|
|
+ fn eq(&self, other: &Self) -> bool {
|
|
|
|
+ self.storage.data_ptr() == other.storage.data_ptr()
|
|
|
|
+ && self.location.generation == other.location.generation
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
|
|
- fn borrow_error(&self) -> BorrowError {
|
|
|
|
- BorrowError::AlreadyBorrowedMut(crate::error::AlreadyBorrowedMutError {
|
|
|
|
- #[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
|
|
- borrowed_mut_at: self.borrowed_mut_at.read().unwrap(),
|
|
|
|
- })
|
|
|
|
|
|
+impl<S: AnyStorage + 'static> Debug for GenerationalPointer<S> {
|
|
|
|
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
+ f.write_fmt(format_args!(
|
|
|
|
+ "{:?}@{:?}",
|
|
|
|
+ self.storage.data_ptr(),
|
|
|
|
+ self.location.generation
|
|
|
|
+ ))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-struct MemoryLocationInner<S = UnsyncStorage> {
|
|
|
|
- data: S,
|
|
|
|
-
|
|
|
|
- #[cfg(any(debug_assertions, feature = "check_generation"))]
|
|
|
|
- generation: std::sync::atomic::AtomicU32,
|
|
|
|
-
|
|
|
|
- #[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
|
|
|
- borrow: MemoryLocationBorrowInfo,
|
|
|
|
|
|
+impl<S: 'static> Clone for GenerationalPointer<S> {
|
|
|
|
+ fn clone(&self) -> Self {
|
|
|
|
+ *self
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
-impl<S> MemoryLocation<S> {
|
|
|
|
- #[allow(unused)]
|
|
|
|
- fn drop(&self)
|
|
|
|
|
|
+impl<S: 'static> Copy for GenerationalPointer<S> {}
|
|
|
|
+
|
|
|
|
+impl<S> GenerationalPointer<S> {
|
|
|
|
+ fn take<T: 'static>(self) -> Option<T>
|
|
where
|
|
where
|
|
- S: AnyStorage,
|
|
|
|
|
|
+ S: Storage<T>,
|
|
{
|
|
{
|
|
- self.0.data.manually_drop();
|
|
|
|
-
|
|
|
|
- #[cfg(any(debug_assertions, feature = "check_generation"))]
|
|
|
|
- {
|
|
|
|
- let new_generation = self.0.generation.load(std::sync::atomic::Ordering::Relaxed) + 1;
|
|
|
|
- self.0
|
|
|
|
- .generation
|
|
|
|
- .store(new_generation, std::sync::atomic::Ordering::Relaxed);
|
|
|
|
- }
|
|
|
|
|
|
+ S::recycle(self).map(|value| *(value.downcast().unwrap()))
|
|
}
|
|
}
|
|
|
|
|
|
- fn replace_with_caller<T>(
|
|
|
|
- &mut self,
|
|
|
|
- value: T,
|
|
|
|
- #[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
|
|
- caller: &'static std::panic::Location<'static>,
|
|
|
|
- ) -> GenerationalBox<T, S>
|
|
|
|
|
|
+ fn set<T>(self, value: T)
|
|
where
|
|
where
|
|
S: Storage<T>,
|
|
S: Storage<T>,
|
|
{
|
|
{
|
|
- self.0.data.set(value);
|
|
|
|
- GenerationalBox {
|
|
|
|
- raw: *self,
|
|
|
|
- #[cfg(any(debug_assertions, feature = "check_generation"))]
|
|
|
|
- generation: self.0.generation.load(std::sync::atomic::Ordering::Relaxed),
|
|
|
|
- #[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
|
|
- created_at: caller,
|
|
|
|
- _marker: PhantomData,
|
|
|
|
- }
|
|
|
|
|
|
+ S::set(self, value)
|
|
}
|
|
}
|
|
-}
|
|
|
|
|
|
|
|
-// We track the generation along with the memory location so that when generational boxes are dropped early, we don't end up dropping the new occupant of the slot
|
|
|
|
-struct LocationKey<S: 'static> {
|
|
|
|
- #[cfg(any(debug_assertions, feature = "check_generation"))]
|
|
|
|
- generation: u32,
|
|
|
|
- location: MemoryLocation<S>,
|
|
|
|
-}
|
|
|
|
|
|
+ #[track_caller]
|
|
|
|
+ fn try_read<T>(self) -> Result<S::Ref<'static, T>, BorrowError>
|
|
|
|
+ where
|
|
|
|
+ S: Storage<T>,
|
|
|
|
+ {
|
|
|
|
+ S::try_read(self)
|
|
|
|
+ }
|
|
|
|
|
|
-impl<S: AnyStorage> LocationKey<S> {
|
|
|
|
- fn exists(&self) -> bool {
|
|
|
|
- #[cfg(any(debug_assertions, feature = "check_generation"))]
|
|
|
|
- return self.generation
|
|
|
|
- == self
|
|
|
|
- .location
|
|
|
|
- .0
|
|
|
|
- .generation
|
|
|
|
- .load(std::sync::atomic::Ordering::Relaxed);
|
|
|
|
- #[cfg(not(any(debug_assertions, feature = "check_generation")))]
|
|
|
|
- return true;
|
|
|
|
|
|
+ #[track_caller]
|
|
|
|
+ fn try_write<T>(self) -> Result<S::Mut<'static, T>, BorrowMutError>
|
|
|
|
+ where
|
|
|
|
+ S: Storage<T>,
|
|
|
|
+ {
|
|
|
|
+ S::try_write(self)
|
|
}
|
|
}
|
|
|
|
|
|
- fn drop(self) {
|
|
|
|
- // If this is the same box we own, we can just drop it
|
|
|
|
- if self.exists() {
|
|
|
|
- S::recycle(&self.location);
|
|
|
|
- }
|
|
|
|
|
|
+ fn recycle(self)
|
|
|
|
+ where
|
|
|
|
+ S: AnyStorage,
|
|
|
|
+ {
|
|
|
|
+ S::recycle(self);
|
|
}
|
|
}
|
|
-}
|
|
|
|
|
|
|
|
-impl<T, S: AnyStorage> From<GenerationalBox<T, S>> for LocationKey<S> {
|
|
|
|
- fn from(value: GenerationalBox<T, S>) -> Self {
|
|
|
|
- Self {
|
|
|
|
- #[cfg(any(debug_assertions, feature = "check_generation"))]
|
|
|
|
- generation: value.generation,
|
|
|
|
- location: value.raw,
|
|
|
|
|
|
+ fn id(&self) -> GenerationalBoxId
|
|
|
|
+ where
|
|
|
|
+ S: AnyStorage,
|
|
|
|
+ {
|
|
|
|
+ GenerationalBoxId {
|
|
|
|
+ data_ptr: self.storage.data_ptr(),
|
|
|
|
+ generation: self.location.generation,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
struct OwnerInner<S: AnyStorage + 'static> {
|
|
struct OwnerInner<S: AnyStorage + 'static> {
|
|
- owned: Vec<LocationKey<S>>,
|
|
|
|
|
|
+ owned: Vec<GenerationalPointer<S>>,
|
|
}
|
|
}
|
|
|
|
|
|
impl<S: AnyStorage> Drop for OwnerInner<S> {
|
|
impl<S: AnyStorage> Drop for OwnerInner<S> {
|
|
fn drop(&mut self) {
|
|
fn drop(&mut self) {
|
|
- for key in self.owned.drain(..) {
|
|
|
|
- key.drop();
|
|
|
|
|
|
+ for location in self.owned.drain(..) {
|
|
|
|
+ location.recycle();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -479,48 +331,35 @@ impl<S: AnyStorage> Owner<S> {
|
|
where
|
|
where
|
|
S: Storage<T>,
|
|
S: Storage<T>,
|
|
{
|
|
{
|
|
- self.insert_with_caller(
|
|
|
|
- value,
|
|
|
|
- #[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
|
|
- std::panic::Location::caller(),
|
|
|
|
- )
|
|
|
|
|
|
+ self.insert_with_caller(value, std::panic::Location::caller())
|
|
}
|
|
}
|
|
|
|
|
|
/// 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.
|
|
/// 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.
|
|
pub fn insert_with_caller<T: 'static>(
|
|
pub fn insert_with_caller<T: 'static>(
|
|
&self,
|
|
&self,
|
|
value: T,
|
|
value: T,
|
|
- #[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
|
|
caller: &'static std::panic::Location<'static>,
|
|
caller: &'static std::panic::Location<'static>,
|
|
) -> GenerationalBox<T, S>
|
|
) -> GenerationalBox<T, S>
|
|
where
|
|
where
|
|
S: Storage<T>,
|
|
S: Storage<T>,
|
|
{
|
|
{
|
|
- let mut location = S::claim();
|
|
|
|
- let key = location.replace_with_caller(
|
|
|
|
- value,
|
|
|
|
- #[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
|
|
|
- caller,
|
|
|
|
- );
|
|
|
|
- self.0.lock().owned.push(key.into());
|
|
|
|
- key
|
|
|
|
|
|
+ let location = S::claim(caller);
|
|
|
|
+ location.set(value);
|
|
|
|
+ self.0.lock().owned.push(location);
|
|
|
|
+ GenerationalBox {
|
|
|
|
+ raw: location,
|
|
|
|
+ _marker: PhantomData,
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
/// 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.
|
|
/// 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.
|
|
|
|
+ #[track_caller]
|
|
pub fn invalid<T: 'static>(&self) -> GenerationalBox<T, S> {
|
|
pub fn invalid<T: 'static>(&self) -> GenerationalBox<T, S> {
|
|
- let location = S::claim();
|
|
|
|
- let generational_box = GenerationalBox {
|
|
|
|
|
|
+ let location = S::claim(std::panic::Location::caller());
|
|
|
|
+ self.0.lock().owned.push(location);
|
|
|
|
+ GenerationalBox {
|
|
raw: location,
|
|
raw: location,
|
|
- #[cfg(any(debug_assertions, feature = "check_generation"))]
|
|
|
|
- generation: location
|
|
|
|
- .0
|
|
|
|
- .generation
|
|
|
|
- .load(std::sync::atomic::Ordering::Relaxed),
|
|
|
|
- #[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
|
|
- created_at: std::panic::Location::caller(),
|
|
|
|
_marker: PhantomData,
|
|
_marker: PhantomData,
|
|
- };
|
|
|
|
- self.0.lock().owned.push(generational_box.into());
|
|
|
|
- generational_box
|
|
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|