Struct someday::Reader

source ·
pub struct Reader<T: Clone> { /* private fields */ }
Expand description

Reader(s) who can atomically read some data T.

Reader’s can cheaply Clone themselves and there is no limit to how many there can be.

Reader’s can cheaply acquire access to the latest data that the Writer has push()’ed by using Reader::head().

This access:

  • Is wait-free and sometimes lock-free
  • Will never block the Writer
  • Will gain a CommitRef of the data T

§Usage

This example covers the typical usage of a Reader:

  • Creating some other Reader’s
  • Acquiring the latest head Commit of data
  • Viewing the data, the timestamp
  • Hanging onto that data for a while
  • Repeat
// Create a Reader/Writer pair of a `String`.
let (reader, writer) = someday::new("".into());

// To clarify the types of these things:
// This is the Reader.
// It can clone itself infinite amount of
// time very cheaply.
let reader: Reader<String> = reader;
for _ in 0..100 {
    // Pretty cheap operation.
    let another_reader = reader.clone();
    // We can send Reader's to other threads.
    std::thread::spawn(move || assert_eq!(another_reader.head().data, ""));
}

// This is the single Writer, it cannot clone itself.
let mut writer: Writer<String> = writer;

// Both Reader and Writer are at timestamp 0 and see no changes.
assert_eq!(writer.timestamp(), 0);
assert_eq!(reader.head().timestamp, 0);
assert_eq!(*writer.data(), "");
assert_eq!(reader.head().data, "");

// Move the Writer into another thread
// and make it do some work in the background.
std::thread::spawn(move || {
    // 1. Append to string
    // 2. Commit it
    // 3. Push so that Readers can see
    // 4. Repeat
    //
    // This is looping at an extremely fast rate
    // and real code probably wouldn't do this, although
    // just for the example...
    loop {
        writer.add(Patch::Ptr(|w, _| w.push_str("abc")));
        writer.commit();
        writer.push();
    }
});

// Even though the Writer _just_ started
// the shared string is probably already
// pretty long at this point.
let head_commit: CommitRef<String> = reader.head();
// Wow, longer than 5,000 bytes!
assert!(head_commit.data.len() > 5_000);

// The timestamp is probably pretty high already too.
assert!(head_commit.timestamp > 500);

// We can continually call `.head()` and keep
// retrieving the latest data. Doing this
// will _not_ block the Writer from continuing.
let mut last_head: CommitRef<String> = reader.head();
let mut new_head:  CommitRef<String> = reader.head();
for _ in 0..10 {
    last_head = reader.head();

    // Wait just a little...
    std::thread::sleep(std::time::Duration::from_millis(10));

    new_head = reader.head();

    // We got new data!
    assert!(last_head != new_head);
    assert!(last_head.timestamp < new_head.timestamp);
}

// We can hold onto these `CommitRef`'s _forever_
// although it means we will be using more memory.
let head_commit: CommitRef<String> = reader.head();

// If we're the last ones holding onto this `Commit`
// we'll be the ones running the `String` drop code here.
drop(head_commit);

Implementations§

source§

impl<T: Clone> Reader<T>

source

pub fn head(&self) -> CommitRef<T>

Acquire the latest CommitRef pushed by the Writer.

This function will never block.

This will retrieve the latest data the Writer is willing to share with Writer::push().

After Writer::push() finishes, it is atomically guaranteed that Reader’s who then call Reader::head() will see those new changes.

// Create a Reader/Writer pair.
let (r, mut w) = someday::new::<String>("".into());

// Both Reader and Writer are at timestamp 0 and see no changes.
assert_eq!(w.timestamp(), 0);
assert_eq!(r.head().timestamp, 0);
assert_eq!(w.data(), "");
assert_eq!(r.head().data, "");

// Writer commits some changes locally.
w.add(Patch::Ptr(|w, _| *w = "hello".into()));
w.commit();

// Writer sees local changes.
assert_eq!(w.timestamp(), 1);
assert_eq!(w.data(), "hello");

// Reader does not, because Writer did not `push()`.
let head: CommitRef<String> = r.head();
assert_eq!(head.timestamp, 0);
assert_eq!(head.data, "");

// Writer pushs to the Readers.
w.push();

// Now Readers see changes.
let head: CommitRef<String> = r.head();
assert_eq!(head.timestamp, 1);
assert_eq!(head.data, "hello");
source

pub fn cache(&mut self) -> CommitRef<T>

Cache a Commit and return it.

Upon first cache or cache after Reader::cache_take, this function will call Reader::head and store it internally for quick access.

Subsequent calls to Reader::cache will return the same Commit forever, and never update.

§Memory usage

Be aware that this causes the Reader to hold onto a CommitRef. As such, the CommitRef will not be dropped until the cache is cleared or this Reader is dropped.

§Example
let (mut r, mut w) = someday::new(());

// Our first cache access, this will call
// `Reader::head()` and save it internally.
let cache: CommitRef<()> = r.cache();
assert_eq!(cache.timestamp, 0);
assert!(r.cache_up_to_date());

// But... the `Writer` continues to push.
w.add_commit_push(|_, _| {});

// Now our cache is technically out-of-date.
assert!(!r.cache_up_to_date());
// Future calls will return the out-of-date cache.
assert_eq!(r.cache().timestamp, 0);
source

pub fn cache_update(&mut self) -> CommitRef<T>

Cache a Commit, updating it if needed, and return it.

This is the same as Reader::cache except it this function will update the internal cache such that it always returns the latest Reader::head.

If the cache is already the same, this is a much cheaper access to the Commit than Reader::head.

let (mut r, mut w) = someday::new(());

// Our first cache access, this will call
// `Reader::head()` and save it internally.
let cache: CommitRef<()> = r.cache_update();
assert_eq!(cache.timestamp, 0);
assert!(r.cache_up_to_date());

// The `Writer` continues to push.
w.add_commit_push(|_, _| {});

// Using `cache_update()`, our cache always is up-to-date.
let cache: CommitRef<()> = r.cache_update();
assert_eq!(cache.timestamp, 1);
assert!(r.cache_up_to_date());
source

pub fn cache_up_to_date(&self) -> bool

Is the Reader::cache up to date?

This returns true if Reader::cache and Reader::head were to return the same CommitRef.

If Reader::cache was never called (or Reader::cache_take’n), then this function returns false.

let (mut r, mut w) = someday::new(());

// There is no cache, this returns `false`.
assert!(!r.cache_up_to_date());

// Set cache.
r.cache();
assert!(r.cache_up_to_date());

// The `Writer` pushes.
w.add_commit_push(|_, _| {});

// Cache is now out-of-date.
assert!(!r.cache_up_to_date());

// Clear the cache.
r.cache_take();
assert!(!r.cache_up_to_date());
source

pub fn cache_take(&mut self) -> Option<CommitRef<T>>

Take the cache out of the Reader.

This returns the internal CommitRef created by Reader::cache and Reader::cache_update.

This returns None if the cache was never created or taken in the past.

let (mut r, mut w) = someday::new(());

// Set cache...
r.cache();
assert!(r.cache_up_to_date());

// ...and take it.
let cache: CommitRef<()> = r.cache_take().unwrap();
assert!(!r.cache_up_to_date());
assert_eq!(cache.timestamp, 0);
source

pub const fn cache_as_ref(&self) -> Option<&CommitRef<T>>

Borrow the internal cache, whether initialized or not.

let (mut r, mut w) = someday::new(());

// No cache, returns None.
assert!(r.cache_as_ref().is_none());

// Set cache, and borrow it.
r.cache();
assert!(r.cache_as_ref().is_some());
source

pub fn reader_count(&self) -> NonZeroUsize

How many Reader’s are there?

This is the same as Writer::reader_count().

let (r, w) = someday::new(());

// `w` + `r` == 2 (Writer's count as a Reader).
assert_eq!(w.reader_count().get(), 2);
assert_eq!(r.reader_count().get(), 2);

let r3 = w.reader();

assert_eq!(w.reader_count().get(), 3);
assert_eq!(r.reader_count().get(), 3);
source

pub fn writer_dropped(&self) -> bool

This returns whether the associated Writer to this Reader has been dropped (or Writer::disconnect’ed).

Note that even if this returns true, Reader::try_into_writer is not guaranteed to succeed as other Reader’s could race towards becoming the new Writer.

It is guaranteed one of them will succeed, but not necessarily this Reader.

let (r, w) = someday::new(());
assert_eq!(r.writer_dropped(), false);

drop(w);
assert_eq!(r.writer_dropped(), true);
source

pub fn connected(&self, other: &Self) -> bool

Are both these Reader’s associated with the same Writer?

This returns true if both self and other are Reader’s from the same Writer.

This means both Reader’s receive the same Commit upon calling Reader::head.

let (r, w) = someday::new(());

// All `Reader`'s read from the same `Writer`.
let r2 = w.reader();
let r3 = r2.clone();
assert!(r.connected(&r2));
assert!(r.connected(&r3));

// This one is completely separate.
let (r4, _) = someday::new(());
assert!(!r.connected(&r4));
source

pub fn connected_writer(&self, writer: &Writer<T>) -> bool

Is this Reader associated with this Writer?

This returns true if self is associated with the passed writer.

This means self receives the Commit’s that writer pushes.

let (r, w) = someday::new(());

// Connected `Reader` <-> `Writer`.
assert!(r.connected_writer(&w));

// This one is completely separate.
let (_, w2) = someday::new(());
assert!(!r.connected_writer(&w2));
source

pub fn try_into_writer(self) -> Result<Writer<T>, Self>

Attempt to transform this Reader into an associated Writer.

If the original Writer associated with this Reader is gone, this function will turn self into a new Writer, while maintaining the connection with any other Reader’s.

Any future Commit pushed by the returned Writer will be observed by other Reader’s.

§Errors

This returns back Err(self) if either:

  1. The associated Writer is still alive
  2. Another Reader is currently in this function, becoming the Writer
§Example
let (r, w) = someday::new(String::from("hello"));

// A secondary `Reader`, forget about this for now.
let r2 = r.clone();

// The `Writer` is still alive... this will fail.
let r: Reader<String> = match r.try_into_writer() {
    Ok(_) => panic!("this can never happen"),
    Err(r) => r,
};

// The `Writer` is now dropped, one of the
// `Reader`'s can now be "promoted".
drop(w);
assert!(r.writer_dropped());
let mut new_writer: Writer<String> = r.try_into_writer().unwrap();

// This new `Writer` is _still_ connected
// to the previous `Reader`'s...!
new_writer.add_commit_push(|w, _| {
    w.push_str(" world!");
});

// The previous `Reader` sees the push!
assert_eq!(r2.head().data, "hello world!");
source

pub fn fork(&self) -> Writer<T>

Fork off from the current Reader::head Commit and create a Writer.

This function is identical Writer::fork, although the Reader’s most recent Commit will be used as the base instead.

let (r, mut w) = someday::new(String::new());

// Connected `Reader` <-> `Writer`.
assert!(r.connected_writer(&w));

// Add local changes, but don't push.
w.add_commit(|s, _| {
    s.push_str("hello");
});
assert_eq!(w.data(), "hello");
assert_eq!(w.timestamp(), 1);
assert_eq!(r.head().data, "");
assert_eq!(r.head().timestamp, 0);

// Fork the _Reader_ off into another `Writer`.
let mut w2 = r.fork();

// It inherits the data of the `Reader`.
assert_eq!(w2.data(), "");
assert_eq!(w2.timestamp(), 0);

// And has no relation to the previous `Writer/Reader`'s.
assert!(!w2.connected(&r));

Trait Implementations§

source§

impl<T> BorshSerialize for Reader<T>
where T: Clone + BorshSerialize,

source§

fn serialize<W: Write>(&self, writer: &mut W) -> Result<()>

This will call self.head().data, then serialize your T.


let (r, _) = someday::new(String::from("hello"));

let encoded = borsh::to_vec(&r).unwrap();
let decoded: Commit<String> = borsh::from_slice(&encoded).unwrap();
assert_eq!(decoded, Commit { timestamp: 0, data: String::from("hello") });
source§

impl<T: Clone + Clone> Clone for Reader<T>

source§

fn clone(&self) -> Reader<T>

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: Debug + Clone> Debug for Reader<T>

source§

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

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

impl<T> Encode for Reader<T>
where T: Clone + Encode,

source§

fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError>

This will call head(), then serialize the resulting CommitRef.


let (r, _) = someday::new(String::from("hello"));
let config = bincode::config::standard();

let encoded = bincode::encode_to_vec(&r, config).unwrap();
let decoded: Commit<String> = bincode::decode_from_slice(&encoded, config).unwrap().0;
assert_eq!(decoded, Commit { timestamp: 0, data: String::from("hello") });
source§

impl<T: Clone> From<&Reader<T>> for CommitRef<T>

source§

fn from(reader: &Reader<T>) -> Self

Calls Reader::head.

let (r, _) = someday::new(String::from("hello"));

let commit_ref: CommitRef<String> = (&r).into();
assert_eq!(commit_ref.data, "hello");
source§

impl<T: Clone> From<&Writer<T>> for Reader<T>

source§

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

Converts to this type from the input type.
source§

impl<T> Serialize for Reader<T>
where T: Clone + Serialize,

source§

fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,

This will call head(), then serialize the resulting CommitRef.


let (r, _) = someday::new(String::from("hello"));

let json = serde_json::to_string(&r).unwrap();
assert_eq!(json, "{\"timestamp\":0,\"data\":\"hello\"}");
source§

impl<T: Clone> TryFrom<Reader<T>> for Writer<T>

source§

fn try_from(reader: Reader<T>) -> Result<Self, Self::Error>

§

type Error = Reader<T>

The type returned in the event of a conversion error.

Auto Trait Implementations§

§

impl<T> RefUnwindSafe for Reader<T>
where T: RefUnwindSafe,

§

impl<T> Send for Reader<T>
where T: Sync + Send,

§

impl<T> Sync for Reader<T>
where T: Sync + Send,

§

impl<T> Unpin for Reader<T>

§

impl<T> UnwindSafe for Reader<T>
where T: RefUnwindSafe,

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