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>
impl<T: 'static> RwData<T>
Sourcepub fn new(value: T) -> Self
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>
impl<T: ?Sized> RwData<T>
Sourcepub fn read<'a>(&'a self, _: &'a Pass) -> &'a T
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.
Sourcepub fn read_as<'a, U: 'static>(&'a self, _: &'a Pass) -> Option<&'a U>
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.
Sourcepub fn declare_as_read(&self)
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.
Sourcepub fn write<'a>(&'a self, _: &'a mut Pass) -> &'a mut T
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.
Sourcepub fn write_as<'a, U: 'static>(&'a self, _: &'a mut Pass) -> Option<&'a mut U>
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.
Sourcepub fn declare_written(&self)
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.
Sourcepub fn map<Ret: 'static>(
&self,
_: &Pass,
map: impl FnMut(&T) -> Ret + 'static,
) -> DataMap<T, Ret>
pub fn map<Ret: 'static>( &self, _: &Pass, 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.
Sourcepub fn try_downcast<U: 'static>(&self) -> Option<RwData<U>>
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 was of type
U, i.e., for unsized types, U was the type parameter
passed when calling RwData::new_unsized.
Sourcepub fn ptr_eq<U: ?Sized>(&self, other: &RwData<U>) -> bool
pub fn ptr_eq<U: ?Sized>(&self, other: &RwData<U>) -> bool
Wether this RwData and another point to the same value
Sourcepub fn has_changed(&self) -> bool
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§impl<W> RwData<W>
impl<W> RwData<W>
Sourcepub fn to_dyn_widget<U: Ui>(&self) -> RwData<dyn Widget<U>>where
W: Widget<U>,
pub fn to_dyn_widget<U: Ui>(&self) -> RwData<dyn Widget<U>>where
W: Widget<U>,
Downcasts RwData<impl Widget<U>> to RwData<dyn Widget<U>>