simplify generational box by compressing debug info
This commit is contained in:
7 files changed
+162
-163
No files matched your search
@@ -20,138 +20,6 @@ mod references;
|
|||||||
mod sync;
|
mod sync;
|
||||||
mod unsync;
|
mod unsync;
|
||||||
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```compile_fail
|
|
||||||
/// let data = String::from("hello world");
|
|
||||||
/// let owner = UnsyncStorage::owner();
|
|
||||||
/// let key = owner.insert(&data);
|
|
||||||
/// drop(data);
|
|
||||||
/// assert_eq!(*key.read(), "hello world");
|
|
||||||
/// ```
|
|
||||||
#[allow(unused)]
|
|
||||||
fn compile_fail() {}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn reused() {
|
|
||||||
let first_ptr;
|
|
||||||
{
|
|
||||||
let owner = UnsyncStorage::owner();
|
|
||||||
first_ptr = owner.insert(1).raw.0.data.data_ptr();
|
|
||||||
drop(owner);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let owner = UnsyncStorage::owner();
|
|
||||||
let second_ptr = owner.insert(1234).raw.0.data.data_ptr();
|
|
||||||
assert_eq!(first_ptr, second_ptr);
|
|
||||||
drop(owner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn leaking_is_ok() {
|
|
||||||
let data = String::from("hello world");
|
|
||||||
let key;
|
|
||||||
{
|
|
||||||
// create an owner
|
|
||||||
let owner = UnsyncStorage::owner();
|
|
||||||
// insert data into the store
|
|
||||||
key = owner.insert(data);
|
|
||||||
// don't drop the owner
|
|
||||||
std::mem::forget(owner);
|
|
||||||
}
|
|
||||||
assert_eq!(
|
|
||||||
key.try_read().as_deref().unwrap(),
|
|
||||||
&"hello world".to_string()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn drops() {
|
|
||||||
let data = String::from("hello world");
|
|
||||||
let key;
|
|
||||||
{
|
|
||||||
// create an owner
|
|
||||||
let owner = UnsyncStorage::owner();
|
|
||||||
// insert data into the store
|
|
||||||
key = owner.insert(data);
|
|
||||||
// drop the owner
|
|
||||||
}
|
|
||||||
assert!(key.try_read().is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn works() {
|
|
||||||
let owner = UnsyncStorage::owner();
|
|
||||||
let key = owner.insert(1);
|
|
||||||
|
|
||||||
assert_eq!(*key.read(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn insert_while_reading() {
|
|
||||||
let owner = UnsyncStorage::owner();
|
|
||||||
let key;
|
|
||||||
{
|
|
||||||
let data: String = "hello world".to_string();
|
|
||||||
key = owner.insert(data);
|
|
||||||
}
|
|
||||||
let value = key.read();
|
|
||||||
owner.insert(&1);
|
|
||||||
assert_eq!(*value, "hello world");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn panics() {
|
|
||||||
let owner = UnsyncStorage::owner();
|
|
||||||
let key = owner.insert(1);
|
|
||||||
drop(owner);
|
|
||||||
|
|
||||||
assert_eq!(*key.read(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn fuzz() {
|
|
||||||
fn maybe_owner_scope(
|
|
||||||
valid_keys: &mut Vec<GenerationalBox<String>>,
|
|
||||||
invalid_keys: &mut Vec<GenerationalBox<String>>,
|
|
||||||
path: &mut Vec<u8>,
|
|
||||||
) {
|
|
||||||
let branch_cutoff = 5;
|
|
||||||
let children = if path.len() < branch_cutoff {
|
|
||||||
rand::random::<u8>() % 4
|
|
||||||
} else {
|
|
||||||
rand::random::<u8>() % 2
|
|
||||||
};
|
|
||||||
|
|
||||||
for i in 0..children {
|
|
||||||
let owner = UnsyncStorage::owner();
|
|
||||||
let key = owner.insert(format!("hello world {path:?}"));
|
|
||||||
valid_keys.push(key);
|
|
||||||
path.push(i);
|
|
||||||
// read all keys
|
|
||||||
println!("{:?}", path);
|
|
||||||
for key in valid_keys.iter() {
|
|
||||||
let value = key.read();
|
|
||||||
println!("{:?}", &*value);
|
|
||||||
assert!(value.starts_with("hello world"));
|
|
||||||
}
|
|
||||||
#[cfg(any(debug_assertions, feature = "check_generation"))]
|
|
||||||
for key in invalid_keys.iter() {
|
|
||||||
assert!(!key.validate());
|
|
||||||
}
|
|
||||||
maybe_owner_scope(valid_keys, invalid_keys, path);
|
|
||||||
invalid_keys.push(valid_keys.pop().unwrap());
|
|
||||||
path.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _ in 0..10 {
|
|
||||||
maybe_owner_scope(&mut Vec::new(), &mut Vec::new(), &mut Vec::new());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The type erased id of a generational box.
|
/// The type erased id of a generational box.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct GenerationalBoxId {
|
pub struct GenerationalBoxId {
|
||||||
@@ -200,7 +68,7 @@ impl<T: 'static, S: AnyStorage> Debug for GenerationalBox<T, S> {
|
|||||||
|
|
||||||
impl<T: 'static, S: Storage<T>> GenerationalBox<T, S> {
|
impl<T: 'static, S: Storage<T>> GenerationalBox<T, S> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn validate(&self) -> bool {
|
pub fn validate(&self) -> bool {
|
||||||
#[cfg(any(debug_assertions, feature = "check_generation"))]
|
#[cfg(any(debug_assertions, feature = "check_generation"))]
|
||||||
{
|
{
|
||||||
self.raw
|
self.raw
|
||||||
@@ -215,6 +83,11 @@ impl<T: 'static, S: Storage<T>> GenerationalBox<T, S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the raw pointer to the value.
|
||||||
|
pub fn raw_ptr(&self) -> *const () {
|
||||||
|
self.raw.0.data.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 {
|
GenerationalBoxId {
|
||||||
@@ -234,12 +107,11 @@ impl<T: 'static, S: Storage<T>> GenerationalBox<T, S> {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
let result = self.raw.0.data.try_read(
|
let result = self.raw.0.data.try_read(
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
||||||
self.created_at,
|
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
GenerationalRefBorrowInfo {
|
GenerationalRefBorrowInfo {
|
||||||
borrowed_at: std::panic::Location::caller(),
|
borrowed_at: std::panic::Location::caller(),
|
||||||
borrowed_from: &self.raw.0.borrow,
|
borrowed_from: &self.raw.0.borrow,
|
||||||
|
created_at: self.created_at,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -272,11 +144,10 @@ impl<T: 'static, S: Storage<T>> GenerationalBox<T, S> {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
let result = self.raw.0.data.try_write(
|
let result = self.raw.0.data.try_write(
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
||||||
self.created_at,
|
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
GenerationalRefMutBorrowInfo {
|
GenerationalRefMutBorrowInfo {
|
||||||
borrowed_from: &self.raw.0.borrow,
|
borrowed_from: &self.raw.0.borrow,
|
||||||
|
created_at: self.created_at,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -360,16 +231,12 @@ 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,
|
&'static self,
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
||||||
created_at: &'static std::panic::Location<'static>,
|
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))] at: GenerationalRefBorrowInfo,
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))] at: GenerationalRefBorrowInfo,
|
||||||
) -> Result<Self::Ref<Data>, BorrowError>;
|
) -> Result<Self::Ref<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,
|
&'static self,
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
||||||
created_at: &'static std::panic::Location<'static>,
|
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))] at: GenerationalRefMutBorrowInfo,
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))] at: GenerationalRefMutBorrowInfo,
|
||||||
) -> Result<Self::Mut<Data>, BorrowMutError>;
|
) -> Result<Self::Mut<Data>, BorrowMutError>;
|
||||||
|
|
||||||
@@ -444,8 +311,10 @@ impl MemoryLocationBorrowInfo {
|
|||||||
|
|
||||||
struct MemoryLocationInner<S = UnsyncStorage> {
|
struct MemoryLocationInner<S = UnsyncStorage> {
|
||||||
data: S,
|
data: S,
|
||||||
|
|
||||||
#[cfg(any(debug_assertions, feature = "check_generation"))]
|
#[cfg(any(debug_assertions, feature = "check_generation"))]
|
||||||
generation: AtomicU32,
|
generation: AtomicU32,
|
||||||
|
|
||||||
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
borrow: MemoryLocationBorrowInfo,
|
borrow: MemoryLocationBorrowInfo,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ impl<T: ?Sized + 'static, R: Deref<Target = T>> Deref for GenerationalRef<R> {
|
|||||||
pub struct GenerationalRefBorrowInfo {
|
pub struct GenerationalRefBorrowInfo {
|
||||||
pub(crate) borrowed_at: &'static std::panic::Location<'static>,
|
pub(crate) borrowed_at: &'static std::panic::Location<'static>,
|
||||||
pub(crate) borrowed_from: &'static crate::MemoryLocationBorrowInfo,
|
pub(crate) borrowed_from: &'static crate::MemoryLocationBorrowInfo,
|
||||||
|
pub(crate) created_at: &'static std::panic::Location<'static>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
@@ -100,6 +101,7 @@ impl<T: ?Sized + 'static, W: DerefMut<Target = T>> DerefMut for GenerationalRefM
|
|||||||
pub struct GenerationalRefMutBorrowInfo {
|
pub struct GenerationalRefMutBorrowInfo {
|
||||||
/// The location where the borrow occurred.
|
/// The location where the borrow occurred.
|
||||||
pub(crate) borrowed_from: &'static crate::MemoryLocationBorrowInfo,
|
pub(crate) borrowed_from: &'static crate::MemoryLocationBorrowInfo,
|
||||||
|
pub(crate) created_at: &'static std::panic::Location<'static>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
|||||||
@@ -56,8 +56,6 @@ impl<T: Sync + Send + 'static> Storage<T> for SyncStorage {
|
|||||||
fn try_read(
|
fn try_read(
|
||||||
&'static self,
|
&'static self,
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
created_at: &'static std::panic::Location<'static>,
|
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
||||||
at: crate::GenerationalRefBorrowInfo,
|
at: crate::GenerationalRefBorrowInfo,
|
||||||
) -> Result<Self::Ref<T>, error::BorrowError> {
|
) -> Result<Self::Ref<T>, error::BorrowError> {
|
||||||
let read = self.0.try_read();
|
let read = self.0.try_read();
|
||||||
@@ -74,7 +72,7 @@ impl<T: Sync + Send + 'static> Storage<T> for SyncStorage {
|
|||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
error::BorrowError::Dropped(ValueDroppedError {
|
error::BorrowError::Dropped(ValueDroppedError {
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
created_at,
|
created_at: at.created_at,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.map(|guard| {
|
.map(|guard| {
|
||||||
@@ -89,8 +87,6 @@ impl<T: Sync + Send + 'static> Storage<T> for SyncStorage {
|
|||||||
fn try_write(
|
fn try_write(
|
||||||
&'static self,
|
&'static self,
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
created_at: &'static std::panic::Location<'static>,
|
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
||||||
at: crate::GenerationalRefMutBorrowInfo,
|
at: crate::GenerationalRefMutBorrowInfo,
|
||||||
) -> Result<Self::Mut<T>, error::BorrowMutError> {
|
) -> Result<Self::Mut<T>, error::BorrowMutError> {
|
||||||
let write = self.0.try_write();
|
let write = self.0.try_write();
|
||||||
@@ -107,7 +103,7 @@ impl<T: Sync + Send + 'static> Storage<T> for SyncStorage {
|
|||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
error::BorrowMutError::Dropped(ValueDroppedError {
|
error::BorrowMutError::Dropped(ValueDroppedError {
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
created_at,
|
created_at: at.created_at,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.map(|guard| {
|
.map(|guard| {
|
||||||
@@ -141,6 +137,7 @@ impl<T: Sync + Send + 'static> Storage<T> for SyncStorage {
|
|||||||
borrow: GenerationalRefBorrowInfo {
|
borrow: GenerationalRefBorrowInfo {
|
||||||
borrowed_at: borrow.borrowed_at,
|
borrowed_at: borrow.borrowed_at,
|
||||||
borrowed_from: borrow.borrowed_from,
|
borrowed_from: borrow.borrowed_from,
|
||||||
|
created_at: borrow.created_at,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -162,6 +159,7 @@ impl<T: Sync + Send + 'static> Storage<T> for SyncStorage {
|
|||||||
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
borrow: GenerationalRefMutBorrowInfo {
|
borrow: GenerationalRefMutBorrowInfo {
|
||||||
borrowed_from: borrow.borrowed_from,
|
borrowed_from: borrow.borrowed_from,
|
||||||
|
created_at: borrow.created_at,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,22 +6,16 @@ use crate::{
|
|||||||
use std::cell::{Ref, RefCell, RefMut};
|
use std::cell::{Ref, RefCell, RefMut};
|
||||||
|
|
||||||
/// A unsync storage. This is the default storage type.
|
/// A unsync storage. This is the default storage type.
|
||||||
|
#[derive(Default)]
|
||||||
pub struct UnsyncStorage(RefCell<Option<Box<dyn std::any::Any>>>);
|
pub struct UnsyncStorage(RefCell<Option<Box<dyn std::any::Any>>>);
|
||||||
|
|
||||||
impl Default for UnsyncStorage {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(RefCell::new(None))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: 'static> Storage<T> for UnsyncStorage {
|
impl<T: 'static> Storage<T> for UnsyncStorage {
|
||||||
type Ref<R: ?Sized + 'static> = GenerationalRef<Ref<'static, R>>;
|
type Ref<R: ?Sized + 'static> = GenerationalRef<Ref<'static, R>>;
|
||||||
type Mut<W: ?Sized + 'static> = GenerationalRefMut<RefMut<'static, W>>;
|
type Mut<W: ?Sized + 'static> = GenerationalRefMut<RefMut<'static, W>>;
|
||||||
|
|
||||||
fn try_read(
|
fn try_read(
|
||||||
&'static self,
|
&'static self,
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
||||||
created_at: &'static std::panic::Location<'static>,
|
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
at: crate::GenerationalRefBorrowInfo,
|
at: crate::GenerationalRefBorrowInfo,
|
||||||
) -> Result<Self::Ref<T>, error::BorrowError> {
|
) -> Result<Self::Ref<T>, error::BorrowError> {
|
||||||
@@ -39,7 +33,7 @@ impl<T: 'static> Storage<T> for UnsyncStorage {
|
|||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
error::BorrowError::Dropped(error::ValueDroppedError {
|
error::BorrowError::Dropped(error::ValueDroppedError {
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
created_at,
|
created_at: at.created_at,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.map(|guard| {
|
.map(|guard| {
|
||||||
@@ -54,8 +48,6 @@ impl<T: 'static> Storage<T> for UnsyncStorage {
|
|||||||
fn try_write(
|
fn try_write(
|
||||||
&'static self,
|
&'static self,
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
created_at: &'static std::panic::Location<'static>,
|
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
|
||||||
at: crate::GenerationalRefMutBorrowInfo,
|
at: crate::GenerationalRefMutBorrowInfo,
|
||||||
) -> Result<Self::Mut<T>, error::BorrowMutError> {
|
) -> Result<Self::Mut<T>, error::BorrowMutError> {
|
||||||
let borrow = self.0.try_borrow_mut();
|
let borrow = self.0.try_borrow_mut();
|
||||||
@@ -71,7 +63,7 @@ impl<T: 'static> Storage<T> for UnsyncStorage {
|
|||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
error::BorrowMutError::Dropped(error::ValueDroppedError {
|
error::BorrowMutError::Dropped(error::ValueDroppedError {
|
||||||
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
created_at,
|
created_at: at.created_at,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.map(|guard| {
|
.map(|guard| {
|
||||||
@@ -121,6 +113,7 @@ impl<T: 'static> Storage<T> for UnsyncStorage {
|
|||||||
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
borrow: GenerationalRefMutBorrowInfo {
|
borrow: GenerationalRefMutBorrowInfo {
|
||||||
borrowed_from: borrow.borrowed_from,
|
borrowed_from: borrow.borrowed_from,
|
||||||
|
created_at: borrow.created_at,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
use generational_box::{AnyStorage, GenerationalBox, UnsyncStorage};
|
||||||
|
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```compile_fail
|
||||||
|
/// let data = String::from("hello world");
|
||||||
|
/// let owner = UnsyncStorage::owner();
|
||||||
|
/// let key = owner.insert(&data);
|
||||||
|
/// drop(data);
|
||||||
|
/// assert_eq!(*key.read(), "hello world");
|
||||||
|
/// ```
|
||||||
|
#[allow(unused)]
|
||||||
|
fn compile_fail() {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn reused() {
|
||||||
|
let first_ptr;
|
||||||
|
{
|
||||||
|
let owner = UnsyncStorage::owner();
|
||||||
|
first_ptr = owner.insert(1).raw_ptr();
|
||||||
|
drop(owner);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let owner = UnsyncStorage::owner();
|
||||||
|
let second_ptr = owner.insert(1234).raw_ptr();
|
||||||
|
assert_eq!(first_ptr, second_ptr);
|
||||||
|
drop(owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn leaking_is_ok() {
|
||||||
|
let data = String::from("hello world");
|
||||||
|
let key;
|
||||||
|
{
|
||||||
|
// create an owner
|
||||||
|
let owner = UnsyncStorage::owner();
|
||||||
|
// insert data into the store
|
||||||
|
key = owner.insert(data);
|
||||||
|
// don't drop the owner
|
||||||
|
std::mem::forget(owner);
|
||||||
|
}
|
||||||
|
assert_eq!(
|
||||||
|
key.try_read().as_deref().unwrap(),
|
||||||
|
&"hello world".to_string()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn drops() {
|
||||||
|
let data = String::from("hello world");
|
||||||
|
let key;
|
||||||
|
{
|
||||||
|
// create an owner
|
||||||
|
let owner = UnsyncStorage::owner();
|
||||||
|
// insert data into the store
|
||||||
|
key = owner.insert(data);
|
||||||
|
// drop the owner
|
||||||
|
}
|
||||||
|
assert!(key.try_read().is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn works() {
|
||||||
|
let owner = UnsyncStorage::owner();
|
||||||
|
let key = owner.insert(1);
|
||||||
|
|
||||||
|
assert_eq!(*key.read(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn insert_while_reading() {
|
||||||
|
let owner = UnsyncStorage::owner();
|
||||||
|
let key;
|
||||||
|
{
|
||||||
|
let data: String = "hello world".to_string();
|
||||||
|
key = owner.insert(data);
|
||||||
|
}
|
||||||
|
let value = key.read();
|
||||||
|
owner.insert(&1);
|
||||||
|
assert_eq!(*value, "hello world");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn panics() {
|
||||||
|
let owner = UnsyncStorage::owner();
|
||||||
|
let key = owner.insert(1);
|
||||||
|
drop(owner);
|
||||||
|
|
||||||
|
assert_eq!(*key.read(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fuzz() {
|
||||||
|
fn maybe_owner_scope(
|
||||||
|
valid_keys: &mut Vec<GenerationalBox<String>>,
|
||||||
|
invalid_keys: &mut Vec<GenerationalBox<String>>,
|
||||||
|
path: &mut Vec<u8>,
|
||||||
|
) {
|
||||||
|
let branch_cutoff = 5;
|
||||||
|
let children = if path.len() < branch_cutoff {
|
||||||
|
rand::random::<u8>() % 4
|
||||||
|
} else {
|
||||||
|
rand::random::<u8>() % 2
|
||||||
|
};
|
||||||
|
|
||||||
|
for i in 0..children {
|
||||||
|
let owner = UnsyncStorage::owner();
|
||||||
|
let key = owner.insert(format!("hello world {path:?}"));
|
||||||
|
valid_keys.push(key);
|
||||||
|
path.push(i);
|
||||||
|
// read all keys
|
||||||
|
println!("{:?}", path);
|
||||||
|
for key in valid_keys.iter() {
|
||||||
|
let value = key.read();
|
||||||
|
println!("{:?}", &*value);
|
||||||
|
assert!(value.starts_with("hello world"));
|
||||||
|
}
|
||||||
|
#[cfg(any(debug_assertions, feature = "check_generation"))]
|
||||||
|
for key in invalid_keys.iter() {
|
||||||
|
assert!(!key.validate());
|
||||||
|
}
|
||||||
|
maybe_owner_scope(valid_keys, invalid_keys, path);
|
||||||
|
invalid_keys.push(valid_keys.pop().unwrap());
|
||||||
|
path.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in 0..10 {
|
||||||
|
maybe_owner_scope(&mut Vec::new(), &mut Vec::new(), &mut Vec::new());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,8 +22,8 @@ pub use dependency::*;
|
|||||||
mod map;
|
mod map;
|
||||||
pub use map::*;
|
pub use map::*;
|
||||||
|
|
||||||
mod comparer;
|
// mod comparer;
|
||||||
pub use comparer::*;
|
// pub use comparer::*;
|
||||||
|
|
||||||
mod global;
|
mod global;
|
||||||
pub use global::*;
|
pub use global::*;
|
||||||
|
|||||||
@@ -14,10 +14,14 @@ pub struct MappedSignal<U: 'static + ?Sized> {
|
|||||||
|
|
||||||
impl MappedSignal<()> {
|
impl MappedSignal<()> {
|
||||||
/// Create a new mapped signal.
|
/// Create a new mapped signal.
|
||||||
pub fn new<T, S: Storage<SignalData<T>>, U: ?Sized>(
|
pub fn new<T, S, U>(
|
||||||
signal: Signal<T, S>,
|
signal: Signal<T, S>,
|
||||||
mapping: impl Fn(&T) -> &U + 'static,
|
mapping: impl Fn(&T) -> &U + 'static,
|
||||||
) -> MappedSignal<S::Ref<U>> {
|
) -> MappedSignal<S::Ref<U>>
|
||||||
|
where
|
||||||
|
S: Storage<SignalData<T>>,
|
||||||
|
U: ?Sized,
|
||||||
|
{
|
||||||
MappedSignal {
|
MappedSignal {
|
||||||
origin_scope: signal.origin_scope(),
|
origin_scope: signal.origin_scope(),
|
||||||
mapping: CopyValue::new(Box::new(move || S::map(signal.read(), &mapping))),
|
mapping: CopyValue::new(Box::new(move || S::map(signal.read(), &mapping))),
|
||||||
|
|||||||
Reference in new issue
Block a user