Struct duat_core::data::RwData

source ·
pub struct RwData<T>
where T: ?Sized + 'static,
{ /* private fields */ }
Expand description

A read-write reference to information, that can tell readers if said information has changed.

The reading part is done through the [ReadableData] trait, as such, you need to import it in order to read the data of this struct.

Unlike RoData, this struct can read and write over itself, and also implements Clone and Into<RoData>, so you can have as many readers and writers as you want.

All reads and writes are thread safe, allowing Duat to run many different tasks at once, without letting the program hang from one particularly slow task (most commonly a slow Widget).

The most common usecase for this data type are Widgets that read from a FileWidget, such as LineNumbers, which do so by holding an RoData<FileWidget<U>, which was acquired from an existing RoData<FileWidget<U>.

struct WidgetThatReadsFromFile<U>
where
    U: Ui,
{
    file: RoData<FileWidget<U>>,
    other_stuff: OtherStuff,
}

Internally, all Widgets are stored inside RwDatas, so access to them is always thread safe and available (read only) to everyone who wants to read them.

Implementations§

source§

impl<T> RwData<T>

source

pub fn new(data: T) -> Self

Returns a new instance of a RwData<T>, 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 a [RwData], see [RwData::new_unsized`].

source§

impl<T> RwData<T>
where T: ?Sized + 'static,

source

pub fn new_unsized<SizedT: 'static>(data: Arc<RwLock<T>>) -> Self

Returns a new instance of RwData<T>, 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.

source

pub fn read(&self) -> RwLockReadGuard<'_, 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 read_write_data = RwData::new("☹️");
let read_only_data = RoData::from(&read_write_data);
let instant = Instant::now();
thread::scope(|scope| {
    scope.spawn(|| {
        let mut read_write = read_write_data.write();
        // Supposedly long computations.
        thread::sleep(Duration::from_millis(100));
        *read_write = "☺️";
    });

    // Just making sure that the read happens slighly after the write.
    thread::sleep(Duration::from_millis(1));

    let read_only = read_only_data.read();
    let time_elapsed = Instant::now().duration_since(instant);
    assert!(time_elapsed >= Duration::from_millis(100));
    assert!(*read_only == "☺️");
});

Note that other reads will NOT block reading in this way, only writes:

let read_write_data = RwData::new("☹️");
let read_only_data = RoData::from(&read_write_data);
let instant = Instant::now();
thread::scope(|scope| {
    scope.spawn(|| {
        let read_only = read_write_data.read();
        // The thread hangs, but reading is still possible.
        thread::sleep(Duration::from_millis(100));
    });

    // Just making sure that this read happens slighly after the last one.
    thread::sleep(Duration::from_millis(1));

    let read_only = read_only_data.read();
    let time_elapsed = Instant::now().duration_since(instant);
    assert!(time_elapsed < Duration::from_millis(100));
});
source

pub fn inspect<U>(&self, f: impl FnOnce(&T) -> U) -> U

Blocking inspection of the inner data.

Also makes it so that has_changed returns false.

§Examples

This method is useful if you want to scope the reading, or need to drop the reference quickly, so it can be written to.

You can do this:

let count = RwData::new(31);
let count_reader = RoData::from(&count);

// The read write counterpart to `inspect`.
count.mutate(|count| {
    *count += 5;
    add_to_count(count)
});

count_reader.inspect(|count| { /* reading operations */ });

*count.write() = new_count();

Instead of this:

let count = RwData::new(31);
let count_reader = RoData::from(&count);

// The read write counterpart to `inspect`.
let mut count_write = count.write();
*count_write += 5;
add_to_count(&mut *count_write);
drop(count_write);

let count_read = count_reader.read();
// reading operations
drop(count_read);

*count.write() = new_count();

Or this:

let count = RwData::new(31);
let count_reader = RoData::from(&count);

// The read write counterpart to `inspect`.
{
    let mut count = count.write();
    *count += 5;
    add_to_count(&mut count)
}

{
    let count = count.read();
    // reading operations
}

*count.write() = new_count();
source

pub fn try_read(&self) -> Option<RwLockReadGuard<'_, 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, Err(TryLockError::WouldBlock)));
source

pub fn try_inspect<U>(&self, f: impl FnOnce(&T) -> U) -> Option<U>

Non blocking inspection of the inner data.

If successful, also makes it so that has_changed returns false.

§Examples

Unlike inspect, can fail to return a reference to the underlying data:

let new_data = RwData::new("hello 👋");

let try_inspect = new_data.mutate(|blocking_mutate| {
    *blocking_mutate = "bye 👋";

    new_data.try_inspect(|try_inspect| *try_inspect == "bye 👋")
});

assert!(matches!(try_inspect, Err(TryLockError::WouldBlock)));
source

pub fn has_changed(&self) -> bool

Wether or not it has changed since it was last read.

A “change” is defined as any time the methods write, mutate, try_write, or try_mutate, 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 [ReadableData].

When first creating a [ReadableData] type, has_changed will return false;

§Examples
use duat_core::data::{ReadableData, RoData, RwData};
let new_data = RwData::new("Initial text");
assert!(!new_data.has_changed());

let first_reader = RoData::from(&new_data);

*new_data.write() = "Final text";

let second_reader = RoData::from(&new_data);

assert!(first_reader.has_changed());
assert!(!second_reader.has_changed());
source

pub fn ptr_eq<U>(&self, other: &(impl Data<U> + ?Sized)) -> bool
where U: ?Sized,

Returns true if both [ReadableData<T>]s point to the same data.

§Examples
let data_1 = RwData::new(false);
let data_1_clone = data_1.clone();

let data_2 = RwData::new(true);

assert!(data_1.ptr_eq(&data_1_clone));
assert!(!data_1.ptr_eq(&data_2));
source

pub fn write(&self) -> ReadWriteGuard<'_, T>

Blocking mutable reference to the information.

Also makes it so that has_changed returns true for [self] or any of its clones, be they RoData or RwData.

§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);
    });
});

In general, try not to juggle multiple &mut handles to RwDatas. A good way of doing that is the RwData::mutate method, which makes it very explicit when a specific handle will be dropped, mitigating the possibility of deadlocks.

source

pub fn try_write(&self) -> Option<ReadWriteGuard<'_, T>>

Non Blocking mutable reference to the information.

Also makes it so that has_changed returns true for [self] or any of its clones, be they RoData or RwData.

§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 (Ok(mut data_1), Ok(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 (Ok(mut data_1), Ok(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.

source

pub fn mutate<R>(&self, f: impl FnOnce(&mut T) -> R) -> R

Blocking mutation of the inner data.

Also makes it so that has_changed returns true for [self] or any of its clones, be they RoData or RwData.

§Safety

This method “technically” has the same problems as RwData::write, where you can deadlock by calling it on multiple instances of RwData, but it makes this much more explicit:

let data_1 = RwData::new('😟');
let data_2 = RwData::new('😭');

thread::scope(|scope| {
    scope.spawn(|| {
        data_1.mutate(|data_1| {
            thread::sleep(Duration::from_millis(100));
            let mut data_2 = data_2.write();
            mem::swap(data_1, &mut *data_2);
        });
    });

    scope.spawn(|| {
        data_2.mutate(|data_2| {
            thread::sleep(Duration::from_millis(100));
            let mut data_1 = data_1.write();
            mem::swap(&mut *data_1, data_2);
        });
    });
});

Generally, you should favor this method for longer functions in which the data is only needed for a short time.

source

pub fn try_mutate<R>(&self, f: impl FnOnce(&mut T) -> R) -> Option<R>

Non blocking mutation of the inner data.

Also makes it so that has_changed returns true for [self] or any of its clones, be they RoData or RwData.

§Safety

Much like RwData::try_write, this also can’t deadlock, failing instead. Generally, you should use this method only when you are fine with not writing the data.

source§

impl<T> RwData<T>
where T: ?Sized + 'static,

source

pub fn data_is<U>(&self) -> bool
where U: 'static,

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 AsAny>; 3] = [
    RwData::new_unsized(Arc::new(RwLock::new(DownCastableString(
        String::from("I can show you the world"),
    )))),
    RwData::new_unsized(Arc::new(RwLock::new(DownCastableString(
        String::from("Shining, shimmering, splendid"),
    )))),
    RwData::new_unsized(Arc::new(RwLock::new(DownCastableChar('🧞')))),
];

assert!(list[0].data_is::<DownCastableString>());
assert!(list[1].data_is::<DownCastableString>());
assert!(list[2].data_is::<DownCastableChar>());
source

pub fn try_downcast<U>(&self) -> Option<RwData<U>>
where U: 'static,

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 AsAny>; 3] = [
    RwData::new_unsized(Arc::new(RwLock::new(DownCastableString(
        String::from("I can show you the world"),
    )))),
    RwData::new_unsized(Arc::new(RwLock::new(DownCastableString(
        String::from("Shining, shimmering, splendid"),
    )))),
    RwData::new_unsized(Arc::new(RwLock::new(DownCastableChar('🧞')))),
];

let maybe_char = list[2].clone().try_downcast::<DownCastableChar>();
assert!(maybe_char.is_ok());
*maybe_char.unwrap().write() = DownCastableChar('👳');

let maybe_string = list[0].clone().try_downcast::<DownCastableChar>();
assert!(maybe_string.is_err());

If you don’t need to write to the data, consider using RwData::inspect_as. If you only need to know if the type matches, consider using RwData::data_is.

source

pub fn inspect_as<U: 'static, R>(&self, f: impl FnOnce(&U) -> R) -> Option<R>

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 AsAny>; 3] = [
    RwData::new_unsized(Arc::new(RwLock::new(DownCastableString(
        String::from("I can show you the world"),
    )))),
    RwData::new_unsized(Arc::new(RwLock::new(DownCastableString(
        String::from("Shining, shimmering, splendid"),
    )))),
    RwData::new_unsized(Arc::new(RwLock::new(DownCastableChar('🧞')))),
];

assert!(matches!(
    list[2].inspect_as::<DownCastableChar, char>(|char| char.0),
    Some('🧞')
));
assert!(matches!(
    list[1].inspect_as::<DownCastableChar, char>(|char| char.0),
    None
));
source

pub fn mutate_as<U: 'static, R>(&self, f: impl FnOnce(&mut U) -> R) -> Option<R>

source§

impl<U> RwData<dyn ActiveWidget<U>>
where U: Ui,

source

pub fn to_passive(self) -> RwData<dyn PassiveWidget<U>>

Trait Implementations§

source§

impl<T> Clone for RwData<T>
where T: ?Sized,

source§

fn clone(&self) -> Self

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<T: ?Sized> Data<T> for RwData<T>

source§

fn to_ro(&self) -> RoData<T>

source§

fn has_changed(&self) -> bool

source§

impl<T> Debug for RwData<T>
where T: ?Sized + Debug,

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<T> Default for RwData<T>
where T: Default,

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl<D> From<&RwData<D>> for BuilderPart<String>
where D: Display,

source§

fn from(value: &RwData<D>) -> Self

Converts to this type from the input type.
source§

impl<T> From<&RwData<T>> for RoData<T>
where T: ?Sized,

source§

fn from(value: &RwData<T>) -> Self

Converts to this type from the input type.
source§

impl<T: ?Sized + Send> Send for RwData<T>

source§

impl<T: ?Sized + Sync> Sync for RwData<T>

Auto Trait Implementations§

§

impl<T> !Freeze for RwData<T>

§

impl<T> !RefUnwindSafe for RwData<T>

§

impl<T> Unpin for RwData<T>
where T: ?Sized,

§

impl<T> !UnwindSafe for RwData<T>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> CloneToUninit for T
where T: Clone,

source§

default unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.