RwData

Struct RwData 

Source
pub struct RwData<T: ?Sized> { /* private fields */ }
Expand description

A container for shared read/write state

This is the struct used internally (and externally) to allow for massively shareable state in duat’s API. Its main purpose is to hold all of the Widgets in Duat, making them available for usage from any function with access to a Pass. However, it can also be used to hold any other type, and also has the ability to notify when changes have taken place.

§Passes

The Pass is a sort of “key” for accessing the value within an RwData, its purpose is to maintain Rust’s number one rule, i.e. one exclusive reference or multiple shared references (mutability XOR aliasing), and that is done by borrowing the Pass mutably or non mutably. That comes with some limitations on how they can be used, mostly the fact that you must mutably borrow all RwDatas that will be used at the same time in order to get multiple mutable references at once.

The use of a Pass for reading/writing to RwDatas confers various benefits:

  • Aside from updating an internal update counter, it is truly zero cost, unlike in the case of a Mutex or RefCell, which have to do checks at runtime. This happens because the Pass has zero size, i.e. it gets removed at compile time.
  • You can’t run into deadlocks like you would be able to when using Mutexes. Neither can you run into panics from reborrowing, like with RefCell.
  • You don’t have to drop a Guard type (like MutexGuard) in order to reborrow from the RwData since borrowing gives you a first class & or &mut, which are much easier to work with.
  • You can do sub borrowings, like &mut data.write(pa).field, given the &mut borrow.

However, there are also a few disadvantages:

  • Sometimes, mutably borrowing multiple things in a single function can be a challenge, although that is mostly mitigated by Pass::write_many.
  • You cannot access the data in a RwData from threads other than the main one, since the Pass is only accessible from it. This isn’t really a disadvantage, since it simplifies thought patterns and eases reasoning about the current state of things.

Implementations§

Source§

impl<T: 'static> RwData<T>

Source

pub fn new(value: T) -> Self

Returns a new RwData<T>

Note that this is only for sized types. For unsized types, the process is a little more convoluted, and you need to use RwData::new_unsized.

Source§

impl<T: ?Sized> RwData<T>

Source

pub fn read<'p>(&'p self, _: &'p Pass) -> &'p T

Reads the value within using a Pass

The consistent use of a Pass for the purposes of reading/writing to the values of RwDatas ensures that no panic or invalid borrow happens at runtime, even while working with untrusted code. More importantly, Duat uses these guarantees in order to give the end user a ridiculous amount of freedom in where they can do things, whilst keeping Rust’s number one rule and ensuring thread safety, even with a relatively large amount of shareable state.

Source

pub fn read_as<'p, U: 'static>(&'p self, _: &'p Pass) -> Option<&'p U>

Reads the value within as U using a Pass

The consistent use of a Pass for the purposes of reading/writing to the values of RwDatas ensures that no panic or invalid borrow happens at runtime, even while working with untrusted code. More importantly, Duat uses these guarantees in order to give the end user a ridiculous amount of freedom in where they can do things, whilst keeping Rust’s number one rule and ensuring thread safety, even with a relatively large amount of shareable state.

Source

pub fn declare_as_read(&self)

Simulates a read without actually reading

This is useful if you want to tell Duat that you don’t want has_changed to return true, but you don’t have a Pass available to read the value.

Source

pub fn write<'p>(&'p self, _: &'p mut Pass) -> &'p mut T

Writes to the value within using a Pass

The consistent use of a Pass for the purposes of reading/writing to the values of RwDatas ensures that no panic or invalid borrow happens at runtime, even while working with untrusted code. More importantly, Duat uses these guarantees in order to give the end user a ridiculous amount of freedom in where they can do things, whilst keeping Rust’s number one rule and ensuring thread safety, even with a relatively large amount of shareable state.

Source

pub fn write_as<'p, U: 'static>(&'p self, _: &'p mut Pass) -> Option<&'p mut U>

Writes to the value within as U using a Pass

The consistent use of a Pass for the purposes of reading/writing to the values of RwDatas ensures that no panic or invalid borrow happens at runtime, even while working with untrusted code. More importantly, Duat uses these guarantees in order to give the end user a ridiculous amount of freedom in where they can do things, whilst keeping Rust’s number one rule and ensuring thread safety, even with a relatively large amount of shareable state.

Source

pub fn write_then<'p, Tup: WriteableTuple<'p, impl Any>>( &'p self, pa: &'p mut Pass, tup_fn: impl FnOnce(&'p T) -> Tup, ) -> (&'p mut T, Tup::Return)

Writes to the value and internal RwData-like structs

This method takes a function that borrows a [WriteableTuple] from self, letting you write to self and the data in the tuple (or single element) at the same time.

This is really useful in a scenario where, for example, your Handle<W> for some widget W holds a Handle<Buffer>, and you wish to access both at the same time, while writing to the former:

use duat::prelude::*;

struct MyWidget {
    text: Text,
    buf: Handle,
}

impl Widget for MyWidget {
    fn update(pa: &mut Pass, handle: &Handle<Self>) {
        let (wid, buf) = handle.write_then(pa, |wid| &wid.buf);
        // Updating the widget and reading/writing from the Buffer at the same time.
        // ...
    }
    // ..
}

You can also return tuples from the function, allowing for access to up to twelve different RwData-like structs:

use duat::prelude::*;

struct MyWidget {
    text: Text,
    buf1: Handle,
    buf2: Handle,
}

impl Widget for MyWidget {
    fn update(pa: &mut Pass, handle: &Handle<Self>) {
        let (wid, (b1, b2)) = handle.write_then(pa, |wid| (&wid.buf1, &wid.buf2));
        // ...
    }
    // ..
}
§Panics

This function will panic if any of the elements of the tuple point to the same data as any other element or self, see Pass::write_many for more information.

Source

pub fn declare_written(&self)

Simulates a write without actually writing

This is useful if you want to tell Duat that you want has_changed to return true, but you don’t have a Pass available to write the value with.

Source

pub fn take(&self, pa: &mut Pass) -> T
where T: Default,

Takes the value within, replacing it with the default

Source

pub fn map<Ret: 'static>( &self, map: impl FnMut(&T) -> Ret + 'static, ) -> DataMap<T, Ret>

Maps the value to another value with a function

This function will return a struct that acts like a “read only” version of RwData, which also maps the value to a return type.

Source

pub fn map_mut<Ret: 'static>( &self, map: impl FnMut(&mut T) -> Ret + 'static, ) -> MutDataMap<T, Ret>

Maps the value to another value with a mutating function

This is useful if you want to repeat a function over and over again in order to get a new different result, whilst mutating the data within.

Source

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

Attempts to downcast an RwData to a concrete type

Returns Some(RwData<U>) if the value within is of type U. For unsized types, U is the type parameter passed when calling RwData::new_unsized.

Source

pub fn ptr_eq<U: ?Sized>(&self, other: &RwData<U>) -> bool

Wether this RwData and another point to the same value

Source

pub fn type_id(&self) -> TypeId

The TypeId of the concrete type within

Source

pub fn is<U: 'static>(&self) -> bool

Wether the concrete TypeId matches that of U

Source

pub fn has_changed(&self) -> bool

Wether someone else called write or write_as since the last read or write

Do note that this DOES NOT mean that the value inside has actually been changed, it just means a mutable reference was acquired after the last call to has_changed.

Some types like Text, and traits like Widget offer has_changed methods, you should try to determine what parts to look for changes.

Generally though, you can use this method to gauge that.

Source

pub fn checker(&self) -> impl Fn() -> bool + Send + Sync + 'static

A function that checks if the data has been updated

Do note that this function will check for the specific RwData that was used in its creation, so if you call read on that specific RwData for example, this function will start returning false.

Source§

impl<W: Widget> RwData<W>

Trait Implementations§

Source§

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

Source§

fn clone(&self) -> Self

Returns a duplicate 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: Debug + ?Sized> Debug for RwData<T>

Source§

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

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

impl<T: Default + 'static> Default for RwData<T>

Source§

fn default() -> Self

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

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

Source§

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

Auto Trait Implementations§

§

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

§

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§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

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

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
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,

Source§

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>,

Source§

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>,

Source§

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.