pub struct RwData<T: ?Sized + 'static> { /* private fields */ }Expand description
A read write shared reference to data
Implementations§
Source§impl<T> RwData<T>
impl<T> RwData<T>
Sourcepub fn new(data: T) -> Self
pub fn new(data: T) -> Self
Returns a new instance of a RwData, assuming that it is
sized.
This has to be sized because of some Rust limitations, as you
cant really pass an unsized argument to a function (for now). If you're looking to store unsized types (dyn Trait, [Type], etc) on an [RwData], see [RwData::new_unsized`].
Source§impl<T: ?Sized> RwData<T>
impl<T: ?Sized> RwData<T>
Sourcepub fn new_unsized<SizedT: 'static>(data: Arc<Mutex<T>>) -> Self
pub fn new_unsized<SizedT: 'static>(data: Arc<Mutex<T>>) -> Self
Returns a new instance of RwData, assuming that it is
unsized.
This method is only required if you’re dealing with types that
may not be Sized (dyn Trait, [Type], etc). If the type
in question is sized, use RwData::new instead.
Sourcepub fn read(&self) -> ReadDataGuard<'_, T>
pub fn read(&self) -> ReadDataGuard<'_, T>
Blocking reference to the information
Also makes it so that has_changed returns false.
§Examples
Since this is a blocking read, the thread will hault while the data is being written to:
let data = RwData::new("☹️");
let data_clone = data.clone();
let instant = Instant::now();
thread::scope(|scope| {
scope.spawn(|| {
let mut read_write = data.write();
// Supposedly long computations.
thread::sleep(Duration::from_millis(150));
*read_write = "☺️";
});
// Just making sure that the read happens slightly after the write.
thread::sleep(Duration::from_millis(10));
let read_only = data_clone.read();
let time_elapsed = Instant::now().duration_since(instant);
assert!(time_elapsed >= Duration::from_millis(100));
assert!(*read_only == "☺️");
});Sourcepub fn try_read(&self) -> Option<ReadDataGuard<'_, T>>
pub fn try_read(&self) -> Option<ReadDataGuard<'_, T>>
Non blocking reference to the information
If successful, also makes it so that has_changed returns
false.
§Examples
Unlike read, can fail to return a reference to the
underlying data:
let new_data = RwData::new("hello 👋");
let mut blocking_write = new_data.write();
*blocking_write = "bye 👋";
let try_read = new_data.try_read();
assert!(matches!(try_read, None));Sourcepub fn has_changed(&self) -> bool
pub fn has_changed(&self) -> bool
Whether or not it has changed since it was last read
A “change” is defined as any time the methods write
or try_write are called on an RwData. Once
has_changed is called, the data will be considered
unchanged since the last has_changed call, for
that specific instance of a RwData.
When first creating a RwData has_changed will return
false, but clones of that RwData will have has_changed
initially return true.
§Examples
use duat_core::data::RwData;
let data = RwData::new("Initial text");
assert!(!data.has_changed());
*data.write() = "Almost final text";
let data_clone1 = data.clone();
assert!(data_clone1.has_changed());
*data.write() = "Final text";
assert!(data_clone1.has_changed());
assert!(!data_clone1.has_changed());Sourcepub fn checker(&self) -> impl Fn() -> bool + Send + Sync + 'static + use<T>
pub fn checker(&self) -> impl Fn() -> bool + Send + Sync + 'static + use<T>
A function that returns true if the data has changed
This is essentially a faster way of writing
let my_data = RwData::new(42);
let checker = {
let my_data = my_data.clone();
move || my_data.has_changed()
};Sourcepub fn write(&self) -> WriteDataGuard<'_, T>
pub fn write(&self) -> WriteDataGuard<'_, T>
Blocking exclusive reference to the information
Also makes it so that has_changed returns true for any of
the clones made from self, but NOT self.
§Safety
Since this is a blocking function, you should be careful about the prevention of deadlocks, one of the few unsafe aspects of code that Rust doesn’t prevent.
As an example, this code will deadlock indefinitely:
let data_1 = RwData::new('😟');
let data_2 = RwData::new('😭');
thread::scope(|scope| {
scope.spawn(|| {
let mut data_1 = data_1.write();
thread::sleep(Duration::from_millis(100));
let mut data_2 = data_2.write();
mem::swap(&mut data_1, &mut data_2);
});
scope.spawn(|| {
let mut data_2 = data_2.write();
thread::sleep(Duration::from_millis(100));
let mut data_1 = data_1.write();
mem::swap(&mut data_1, &mut data_2);
});
});Sourcepub fn try_write(&self) -> Option<WriteDataGuard<'_, T>>
pub fn try_write(&self) -> Option<WriteDataGuard<'_, T>>
Non Blocking mutable reference to the information
Also makes it so that has_changed returns true for any of
the clones made from self, but NOT self.
§Safety
Unlike RwData::write, this method cannot cause deadlocks,
returning an Err instead.
let data_1 = RwData::new('😀');
let data_2 = RwData::new('😁');
thread::scope(|scope| {
scope.spawn(|| {
let mut data_1 = data_1.try_write();
thread::sleep(Duration::from_millis(100));
let mut data_2 = data_2.try_write();
if let (Some(mut data_1), Some(mut data_2)) = (data_1, data_2) {
mem::swap(&mut data_1, &mut data_2);
}
});
scope.spawn(|| {
let mut data_2 = data_2.try_write();
thread::sleep(Duration::from_millis(100));
let mut data_1 = data_1.try_write();
if let (Some(mut data_1), Some(mut data_2)) = (data_1, data_2) {
mem::swap(&mut data_1, &mut data_2);
}
});
});
// Two swaps will happen.
assert_eq!(*data_1.read(), '😀');
assert_eq!(*data_2.read(), '😁');The downside is that you may not want it to fail ever, in
which case, you should probably use RwData::write.
Sourcepub fn data_is<U: ?Sized + 'static>(&self) -> bool
pub fn data_is<U: ?Sized + 'static>(&self) -> bool
Returns true if the data is of the concrete type T
§Examples
You may want this method if you’re storing a list of
RwData<dyn Trait>, and want to know, at runtime, what type
each element is:
let list: [RwData<dyn Display>; 3] = [
RwData::new_unsized::<String>(Arc::new(Mutex::new(String::from(
"I can show you the world",
)))),
RwData::new_unsized::<String>(Arc::new(Mutex::new(String::from(
"Shining, shimmering, splendid",
)))),
RwData::new_unsized::<char>(Arc::new(Mutex::new('🧞'))),
];
assert!(list[0].data_is::<String>());
assert!(list[1].data_is::<String>());
assert!(list[2].data_is::<char>());Sourcepub fn try_downcast<U: 'static>(&self) -> Option<RwData<U>>
pub fn try_downcast<U: 'static>(&self) -> Option<RwData<U>>
Tries to downcast to a concrete type
§Examples
You may want this method if you’re storing a list of
RwData<dyn Trait>, and want to know, at runtime, what type
each element is:
let list: [RwData<dyn Display>; 3] = [
RwData::new_unsized::<String>(Arc::new(Mutex::new(String::from(
"I can show you the world",
)))),
RwData::new_unsized::<String>(Arc::new(Mutex::new(String::from(
"Shining, shimmering, splendid",
)))),
RwData::new_unsized::<char>(Arc::new(Mutex::new('🧞'))),
];
let maybe_char = list[2].clone().try_downcast::<char>();
assert!(maybe_char.is_some());
*maybe_char.unwrap().write() = '👳';
let maybe_string = list[0].clone().try_downcast::<char>();
assert!(maybe_string.is_none());If you don’t need to keep a RwData<U>, consider just using
RwData::read_as. If you only need to know if the type
matches, consider using RwData::data_is.
Sourcepub fn read_as<U: 'static>(&self) -> Option<ReadDataGuard<'_, U>>
pub fn read_as<U: 'static>(&self) -> Option<ReadDataGuard<'_, U>>
Blocking inspection of the inner data
§Examples
You may want this method if you’re storing a list of
RwData<dyn Trait>, and want to know, at runtime, what type
each element is:
let list: [RwData<dyn Display>; 3] = [
RwData::new_unsized::<String>(Arc::new(Mutex::new(String::from(
"I can show you the world",
)))),
RwData::new_unsized::<String>(Arc::new(Mutex::new(String::from(
"Shining, shimmering, splendid",
)))),
RwData::new_unsized::<char>(Arc::new(Mutex::new('🧞'))),
];
assert!(matches!(
list[2].read_as::<char>().map(|c| c.len_utf8()),
Some(4)
));
assert!(matches!(
list[1].read_as::<char>().map(|c| c.to_ascii_uppercase()),
None
));