Struct RwData

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

A read write shared reference to data

Implementations§

Source§

impl<T> RwData<T>

Source

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>

Source

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.

Source

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 == "☺️");
});
Source

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));
Source

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());
Source

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()
};
Source

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

Returns true if both RwDatas 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) -> 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);
    });
});
Source

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.

Source

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>());
Source

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.

Source

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
));
Source

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

Source§

impl<I: ?Sized + Send + 'static> RwData<I>

Source

pub fn map<O>(&self, f: impl FnMut(&I) -> O + Send + 'static) -> DataMap<I, O>

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

Source§

fn default() -> Self

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

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

Source§

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

Converts to this type from the input type.
Source§

impl From<RwData<PathBuf>> for BuilderPart<String, PathBuf>

Source§

fn from(value: RwData<PathBuf>) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl<T> !Freeze for RwData<T>

§

impl<T> !RefUnwindSafe for RwData<T>

§

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

§

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

§

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