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.

§Passes

The Pass is a sort of “key” for accessing the value within an RwData, it’s purpose is to maintain Rust’s number one rule, i.e. one exclusive reference or multiple shared references, and that is done by borrowing the Pass mutably or non mutably. That comes with some limitations, of course, mainly that you can’t really mutate two RwDatas at the same time, even if it is known that they don’t point to the same data.

There are some common exceptions to this, where Duat provides some safe way to do that when it is known that the two types are not the same.

§Not Send/Sync

Internally, the RwData makes use of an Arc<RefCell>. The usage of an Arc<RefCell> over an Arc<Mutex> is, i’ve assumed, a necessary evil in order to preserve the aforementioned rule. But the lack of Send/Sync does confer the RwData some advantages:

  • Deadlocks are impossible, being replaced by much easier to debug panics.
  • The order in which data is accessed doesn’t matter, unlike with Mutexes.
  • Performance of unlocking and cloning should generally be better, since no atomic operations are done (I actually managed to observe this, where in my rudimentary benchmarks against neovim, the Arc<Mutex> version was very frequently losing to a comparable neovim build.

However, I admit that there are also some drawbacks, the most notable being the difficulty of reading or writing to Text from outside of the main thread. But for the most common usecase where that will be needed (Parsers), a Send/Sync solution will be provided soon.

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<'a>(&'a self, _: &'a Pass) -> &'a 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<'a, U: 'static>(&'a self, _: &'a Pass) -> Option<&'a 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<'a>(&'a self, _: &'a mut Pass) -> &'a 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<'a, U: 'static>(&'a self, _: &'a mut Pass) -> Option<&'a 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 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 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 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 + 'static> Send for RwData<T>

Source§

impl<T: ?Sized + 'static> 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 + Sync + Send>

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.