pub struct Writer<T: Clone> { /* private fields */ }
Expand description
The single Writer
of some data T
.
The Writer
:
- Stores your
Patch
’s withadd()
- Actually applies them to
T
bycommit()
’ing - Can
push()
so thatReader
’s can see the changes
The Writer
can also generate infinite Reader
’s with Writer::reader()
.
§Invariants
Some invariants that the Writer
upholds, that you can rely on:
Invariant | Description |
---|---|
No “rebasing” | Writer::timestamp() will always be greater than or equal to the Reader::head() ’s timestamp. |
PartialEq | If the Writer::timestamp() is the same as the Reader::head() ’s timestamp, the data T is the same as well (as long as Patch ’s are deterministic). This can serve as a very cheap way to compare data (just compare the timestamps). |
1 Writer | There can only ever be 1 Writer at any given moment (at least, without shared mutual exclusion like Arc + Mutex ). |
Poison | If a Writer panics mid-push() , the data can only be poisoned on the Writer side - i.e. Reader ’s will be completely fine if the Writer panics, other Writer ’s (e.g Arc<Mutex<Writer<T>>> ) may panic as well on any function that accesses T . |
§Usage
This example covers the typical usage of a Writer
:
- Creating some
Reader
’s - Adding some
Patch
’s - Viewing the staged
Patch
’s, modifying them - Committing those changes
- Pushing those changes to the
Reader
’s
use someday::{*,info::*};
// Create a Reader/Writer pair that can "apply"
// the `PatchString` patch to `String`'s.
let (r, w) = someday::new("".into());
// To clarify the types of these things:
// This is the Reader.
// It can clone itself an infinite
// amount of time very cheaply.
let r: Reader<String> = r;
for _ in 0..10_000 {
let another_reader = r.clone(); // akin to Arc::clone()
}
// This is the single Writer, it cannot clone itself.
let mut w: Writer<String> = w;
// 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, "");
// The Writer can add many `Patch`'s
w.add(Patch::Ptr(|w, _| w.push_str("abc")));
w.add(Patch::Ptr(|w, _| w.push_str("def")));
w.add(Patch::Ptr(|w, _| w.push_str("ghi")));
w.add(Patch::Ptr(|w, _| w.push_str("jkl")));
// But `add()`'ing does not actually modify the
// local (Writer) or remote (Readers) data, it
// just "stages" them.
assert_eq!(w.timestamp(), 0);
assert_eq!(r.head().timestamp, 0);
assert_eq!(w.data(), "");
assert_eq!(r.head().data, "");
// We can see our "staged" patches here.
let staged = w.staged();
assert_eq!(staged.len(), 4);
// Let's actually remove a patch.
staged.remove(3); // w.push_str("jkl")
// Okay, now let's commit locally.
let commit_info: CommitInfo = w.commit();
// We applied 3 patches in total.
assert_eq!(commit_info.patches, 3);
// And added 1 commit (timestamp).
assert_eq!(w.timestamp(), 1);
// We haven't pushed yet, so the Readers
// are still un-aware of our local changes.
assert_eq!(w.timestamp(), 1);
assert_eq!(r.head().timestamp, 0);
assert_eq!(w.data(), "abcdefghi");
assert_eq!(r.head().data, "");
// Now we push.
let push_info: PushInfo = w.push();
// We pushed 1 commit in total.
assert_eq!(push_info.commits, 1);
// Our staged functions are now gone.
assert_eq!(w.staged().len(), 0);
// The Readers are now in sync.
assert_eq!(w.timestamp(), 1);
assert_eq!(r.head().timestamp, 1);
assert_eq!(w.data(), "abcdefghi");
assert_eq!(r.head().data, "abcdefghi");
Implementations§
source§impl<T: Clone> Writer<T>
impl<T: Clone> Writer<T>
sourcepub fn add(&mut self, patch: Patch<T>)
pub fn add(&mut self, patch: Patch<T>)
Add a Patch
to apply to the data T
This does not execute the Patch
immediately,
it will only store it for later usage.
Commit
-like operations are when these
functions are applied to your data, e.g. Writer::commit()
.
let (r, mut w) = someday::new::<usize>(0);
// Add a patch.
w.add(Patch::Ptr(|w, _| *w += 1));
// It hasn't been applied yet.
assert_eq!(w.staged().len(), 1);
// Now it has.
w.commit();
assert_eq!(w.staged().len(), 0);
sourcepub fn commit(&mut self) -> CommitInfo
pub fn commit(&mut self) -> CommitInfo
Apply all the Patch
’s that were add()
’ed
The new Commit
created from this will become
the Writer
’s new Writer::head()
.
You can commit()
multiple times and it will
only affect the Writer
’s local data.
You can choose when to publish those changes to
the Reader
’s with Writer::push()
.
The CommitInfo
object returned is just a container
for some metadata about the commit()
operation.
let (r, mut w) = someday::new::<usize>(0);
// Timestamp is 0.
assert_eq!(w.timestamp(), 0);
// Add and commit a patch.
w.add(Patch::Ptr(|w, _| *w += 123));
w.commit();
assert_eq!(w.timestamp(), 1);
assert_eq!(w.head().data, 123);
§Timestamp
This will increment the Writer
’s local Timestamp
by 1
,
but only if there were Patch
’s to actually apply. In other
words, if you did not call add()
before this,
commit()
will do nothing.
let (r, mut w) = someday::new::<usize>(0);
// Timestamp is 0.
assert_eq!(w.timestamp(), 0);
// We didn't `add()` anything, but commit anyway.
let commit_info = w.commit();
assert_eq!(commit_info.patches, 0);
assert_eq!(commit_info.timestamp_diff, 0);
// There was nothing to commit,
// so our timestamp did not change.
assert_eq!(w.timestamp(), 0);
assert_eq!(w.head().data, 0);
sourcepub fn add_commit<P, Output>(&mut self, patch: P) -> (CommitInfo, Output)
pub fn add_commit<P, Output>(&mut self, patch: P) -> (CommitInfo, Output)
This function combines add()
and commit()
together.
Since these actions are done together, a return value is allowed to be specified.
This function will apply your Writer::staged()
patches
first, then your input patch
, then commit()
them.
§Example
If you’d like to receive a large chunk of data
from your T
instead of throwing it away:
// Very expensive data.
let vec = (0..100_000).map(|i| format!("{i}")).collect();
let (_, mut w) = someday::new::<Vec<String>>(vec);
assert_eq!(w.timestamp(), 0);
assert_eq!(w.timestamp_remote(), 0);
// Add some patches normally.
// These will be applied in `add_commit()` below.
for i in 100_000..200_000 {
w.add(Patch::boxed(move |w: &mut Vec<String>, _| {
w.push(format!("{i}"));
}));
}
let (commit_info, r) = w.add_commit(|w, _| {
// Swap our value, and get back the strings.
// This implicitly becomes our <Output> (Vec<String>).
std::mem::take(w)
});
// We got our 200,000 `String`'s back
// instead of dropping them!
let r: Vec<String> = r;
assert_eq!(r.len(), 200_000);
assert_eq!(commit_info.patches, 100_001); // 100_000 normal patches + 1 `add_commit()`
assert_eq!(commit_info.timestamp_diff, 1);
// We got back our original strings.
for (i, string) in r.into_iter().enumerate() {
assert_eq!(format!("{i}"), string);
}
// And the `Patch` got applied to the `Writer`'s data,
// but hasn't been `push()`'ed yet.
assert!(w.data().is_empty());
assert_eq!(w.timestamp(), 1);
assert_eq!(w.timestamp_remote(), 0);
§Generics
The generic inputs are:
Patch
Output
Patch
is the same as Writer::add()
however, it has a
-> Output
value associated with it, this is defined by
you, using the Output
generic.
§Timestamp
This function will always increment the Writer
’s local Timestamp
by 1
.
sourcepub fn add_commit_push<Patch, Output>(
&mut self,
patch: Patch
) -> (PushInfo, Output, Option<Output>)
pub fn add_commit_push<Patch, Output>( &mut self, patch: Patch ) -> (PushInfo, Output, Option<Output>)
This function combines add()
, commit()
, push()
together.
Since these actions are done together, return values are allowed
to be specified where they wouldn’t otherwise be.
The input Patch
no longer has to be Send + 'static
either.
This allows you to specify any arbitrary return value from
your Patch
’s, even return values from your T
itself.
For example, if you’d like to receive a large chunk of data
from your T
instead of throwing it away:
// Very expensive data.
let vec = (0..100_000).map(|i| format!("{i}")).collect();
let (_, mut w) = someday::new::<Vec<String>>(vec);
assert_eq!(w.timestamp(), 0);
assert_eq!(w.timestamp_remote(), 0);
let (info, r1, r2) = w.add_commit_push(|w, _| {
// Swap our value, and get back the strings.
// This implicitly becomes our <Output> (Vec<String>).
std::mem::take(w)
});
// We got our 100,000 `String`'s back
// instead of dropping them!
let r1: Vec<String> = r1;
// If `Writer` reclaimed data and applied our
// `Patch` to it, it also got returned!
let r2: Option<Vec<String>> = r2;
// And, some push info.
let info: PushInfo = info;
// We got back our original strings.
for (i, string) in r1.into_iter().enumerate() {
assert_eq!(format!("{i}"), string);
}
// If the `Writer` reclaimed data,
// then `r2` will _always_ be a `Some`.
if info.reclaimed {
// This also contains 100,000 strings.
assert!(r2.is_some());
}
// And the `Patch` got applied to the `Writer`'s data.
assert!(w.data().is_empty());
assert_eq!(w.timestamp(), 1);
assert_eq!(w.timestamp_remote(), 1);
§Generics
The generic inputs are:
Patch
Output
Patch
is the same as Writer::add()
however, it has a
-> Output
value associated with it, this is defined by
you, using the Output
generic.
§Returned Tuple
The returned tuple is contains the regular PushInfo
along with a Output
and Option<Output>
.
The Output
is the data returned by operating on the Writer
’s side
of the data.
The Option<Output>
is Some
if the Writer
reclaimed the Reader
’s
side of the data, and re-applied your Patch
- it returns it instead
of dropping it. This means that if PushInfo
’s reclaimed
is
true
, this Option<Output>
will always be Some
.
§Timestamp
This function will always increment the Writer
’s local Timestamp
by 1
.
sourcepub fn add_commit_push_wait<Patch, Output>(
&mut self,
duration: Duration,
patch: Patch
) -> (PushInfo, Output, Option<Output>)
pub fn add_commit_push_wait<Patch, Output>( &mut self, duration: Duration, patch: Patch ) -> (PushInfo, Output, Option<Output>)
This is the same as Self::add_commit_push()
with Self::push_wait()
semantics.
See push_wait()
’s documentation for more info.
let (r, mut w) = someday::new::<String>("".into());
let commit = r.head();
spawn(move || {
// This `Reader` is holding onto the old data.
let moved = commit;
// But will let go after 1 millisecond.
sleep(Duration::from_millis(1));
});
// Wait 250 milliseconds before resorting to cloning data.
let (push_info, _, _) = w.add_commit_push_wait(
Duration::from_millis(250),
|w, _| w.push_str("abc"),
);
// We pushed 1 commit.
assert_eq!(push_info.commits, 1);
// And we successfully reclaimed the old data cheaply.
assert_eq!(push_info.reclaimed, true);
sourcepub fn add_commit_push_do<Patch, Output, F, R>(
&mut self,
f: F,
patch: Patch
) -> (PushInfo, Output, Option<Output>, R)
pub fn add_commit_push_do<Patch, Output, F, R>( &mut self, f: F, patch: Patch ) -> (PushInfo, Output, Option<Output>, R)
This is the same as Self::add_commit_push()
with Self::push_do()
semantics.
See push_do()
’s documentation for more info.
let (r, mut w) = someday::new::<String>("".into());
let head = r.head();
spawn(move || {
// This `Reader` is holding onto the old data.
let moved = head;
// But will let go after 100 milliseconds.
sleep(Duration::from_millis(100));
});
// Some work to be done.
let mut hashmap = HashMap::<usize, String>::new();
let mut vec = vec![];
// The actual `Patch` on our data.
let patch = |w: &mut String, _: &_| w.push_str("abc");
// The closure to do arbitrary things while pushing.
let closure = || {
// While we're waiting, let's get some work done.
// Add a bunch of data to this HashMap.
(0..1_000).for_each(|i| {
hashmap.insert(i, format!("{i}"));
});
// Add some data to the vector.
(0..1_000).for_each(|_| {
vec.push(format!("aaaaaaaaaaaaaaaa"));
}); // <- `add_commit_push_do()` returns `()`
}; // although we could return anything
// and it would be binded to `return_value`
// Pass in a closure, so that we can do
// arbitrary things in the meanwhile...!
let (push_info, _, _, return_value) = w.add_commit_push_do(closure, patch);
// At this point, the old `Reader`'s have
// probably all dropped their old references
// and we can probably cheaply reclaim our
// old data back.
// And yes, looks like we got it back cheaply:
assert_eq!(push_info.reclaimed, true);
// And we did some work
// while waiting to get it:
assert_eq!(hashmap.len(), 1_000);
assert_eq!(vec.len(), 1_000);
assert_eq!(return_value, ());
sourcepub fn add_commit_push_clone<Patch, Output>(
&mut self,
patch: Patch
) -> (PushInfo, Output, Option<Output>)
pub fn add_commit_push_clone<Patch, Output>( &mut self, patch: Patch ) -> (PushInfo, Output, Option<Output>)
This is the same as Self::add_commit_push()
with Self::push_clone()
semantics.
See push_clone()
’s documentation for more info.
let (r, mut w) = someday::new::<String>("".into());
let (push_info, _, _) = w.add_commit_push_clone(|w, _| {
w.push_str("abc");
});
assert_eq!(push_info.commits, 1);
assert_eq!(push_info.reclaimed, false);
source§impl<T: Clone> Writer<T>
impl<T: Clone> Writer<T>
sourcepub fn reader(&self) -> Reader<T>
pub fn reader(&self) -> Reader<T>
Cheaply construct a Reader
connected to this Writer
This creates a new Reader
that can read all the
data push()
’ed from this Writer
.
There is no limit on concurrent Reader
’s.
let (r, mut w) = someday::new::<usize>(0);
// Create 100 more readers.
let readers: Vec<Reader<usize>> = vec![w.reader(); 100];
sourcepub const fn data(&self) -> &T
pub const fn data(&self) -> &T
View the Writer
’s local data
This is the Writer
’s local data that may or may
not have been push()
’ed yet.
commit()
’ing will apply the
add()
’ed Patch
’s directly to this data.
If push()
is called, this would be the
new data that Reader
’s would see.
let (r, mut w) = someday::new::<usize>(0);
// No changes yet.
assert_eq!(*w.data(), 0);
assert_eq!(r.head().data, 0);
// Writer commits some changes.
w.add(Patch::Ptr(|w, _| *w += 1));
w.commit();
// Writer sees local change.
assert_eq!(*w.data(), 1);
// Reader doesn't see change.
assert_eq!(r.head().data, 0);
sourcepub fn tx(&mut self) -> Transaction<'_, T>
pub fn tx(&mut self) -> Transaction<'_, T>
Mutate the Writer
’s local data without going through a Patch
.
This function gives you direct access to the
underlying local T
via a Transaction
.
In order to prevent out-of-sync situations, Transaction
will
unconditionally add a Patch
that clones data after it has been drop
’ed.
This is cheaper than Patch
if you had already planned to clone data anyway.
See Transaction
for more details.
sourcepub fn data_remote(&self) -> &T
pub fn data_remote(&self) -> &T
View the latest copy of data Reader
’s have access to
let (_, mut w) = someday::new::<usize>(0);
// Writer commits some changes.
w.add(Patch::Ptr(|w, _| *w += 1));
w.commit();
// Writer sees local change.
assert_eq!(*w.data(), 1);
// But they haven't been pushed to the remote side
// (Readers can't see them)
assert_eq!(*w.data_remote(), 0);
sourcepub const fn head(&self) -> &Commit<T>
pub const fn head(&self) -> &Commit<T>
View the Writer
’s local “head” Commit
This is the latest, and local Commit
from the Writer
.
Calling commit()
would make that new
Commit
be the return value for this function.
Reader
’s may or may not see this Commit
yet.
let (_, mut w) = someday::new::<usize>(500);
// No changes yet.
let commit: &Commit<usize> = w.head();
assert_eq!(commit.timestamp, 0);
assert_eq!(commit.data, 500);
// Writer commits some changes.
w.add(Patch::Ptr(|w, _| *w += 1));
w.commit();
// Head commit is now changed.
let commit: &Commit<usize> = w.head();
assert_eq!(commit.timestamp, 1);
assert_eq!(commit.data, 501);
sourcepub fn head_remote(&self) -> &Commit<T>
pub fn head_remote(&self) -> &Commit<T>
View the Reader
’s latest “head” Commit
This is the latest Commit
the Reader
’s can see.
Calling push()
would update the Reader
’s head Commit
.
let (_, mut w) = someday::new::<usize>(500);
// No changes yet.
let commit: &Commit<usize> = w.head_remote();
assert_eq!(commit.timestamp, 0);
assert_eq!(commit.data, 500);
// Writer commits & pushes some changes.
w.add(Patch::Ptr(|w, _| *w += 1));
w.commit();
w.push();
// Reader's head commit is now changed.
let commit: &Commit<usize> = w.head_remote();
assert_eq!(commit.timestamp, 1);
assert_eq!(commit.data, 501);
sourcepub fn head_remote_ref(&self) -> CommitRef<T>
pub fn head_remote_ref(&self) -> CommitRef<T>
Cheaply acquire ownership of the Reader
’s latest “head” Commit
This is the latest Commit
the Reader
’s can see.
Calling push()
would update the Reader
’s head Commit
.
This is an shared “owned” Commit
(it uses Arc
internally).
let (r, mut w) = someday::new::<usize>(0);
// Reader gets a reference.
let reader: CommitRef<usize> = r.head();
// Writer gets a reference.
let writer: CommitRef<usize> = w.head_remote_ref();
// Reader drops their reference.
// Nothing happens, an atomic count is decremented.
drop(reader);
// Writer drops their reference.
// They were the last reference, so they are
// responsible for deallocating the backing data.
drop(writer);
sourcepub fn staged(&mut self) -> &mut Vec<Patch<T>>
pub fn staged(&mut self) -> &mut Vec<Patch<T>>
All the Patch
’s that haven’t been commit()
’ed yet, aka, “staged” changes
You are allowed to do anything to these Patch
’s as they haven’t
been committed yet and the Writer
does not necessarily need them.
You can use something like .staged().drain(..)
to get back all the Patch
’s.
All the Patch
’s that have been commit()
’ed but not yet
push()
’ed are safely stored internally by the Writer
.
let (r, mut w) = someday::new::<String>("".into());
// Add some changes.
w.add(Patch::Ptr(|w, _| w.push_str("abc")));
// We see and mutate the staged changes.
assert_eq!(w.staged().len(), 1);
// Let's actually remove that change.
let removed = w.staged().remove(0);
assert_eq!(w.staged().len(), 0);
sourcepub const fn committed_patches(&self) -> &Vec<Patch<T>>
pub const fn committed_patches(&self) -> &Vec<Patch<T>>
All the Patch
’s that have been commit()
’ed but not yet push()
’ed
You are not allowed to mutate these Patch
’s as they haven’t been
push()
’ed yet and the Writer
may need them in the future.
let (r, mut w) = someday::new::<String>("".into());
// Commit some changes.
w.add(Patch::Ptr(|w, _| w.push_str("abc")));
w.commit();
// We can see but not mutate functions.
assert_eq!(w.committed_patches().len(), 1);
sourcepub fn head_count(&self) -> NonZeroUsize
pub fn head_count(&self) -> NonZeroUsize
How many Reader
’s are currently accessing
the current Reader
head Commit
?
Note that this will always at least return 2
, as the
Writer
carries 2 strong references to the backing data T
.
let (_, mut w) = someday::new::<String>("".into());
// The Writer, `w` holds 2 strong counts.
assert_eq!(w.head_count().get(), 2);
// Create and leak 8 Reader's.
// Note however, the above Reader's
// do not have strong references to the
// underlying data, so they don't count.
for i in 0..8 {
let reader = w.reader();
std::mem::forget(reader);
}
let r = w.reader();
assert_eq!(w.head_count().get(), 2);
// Leak the actual data 8 times.
for i in 0..8 {
let head: CommitRef<String> = r.head();
std::mem::forget(head);
}
// Now there are 10 strong references.
// (which will never be reclaimed since
// we just leaked them)
assert_eq!(w.head_count().get(), 10);
sourcepub fn reader_count(&self) -> NonZeroUsize
pub fn reader_count(&self) -> NonZeroUsize
How many Reader
’s are there?
Unlike Writer::head_count()
, this doesn’t count references
to the current data, it counts how many Reader
objects are in existence.
Note that this will always at least return 1
,
as the Writer
counts as a Reader
.
let (r, mut w) = someday::new::<String>("".into());
// 2 Reader's (the Writer counts as a Reader).
assert_eq!(w.reader_count().get(), 2);
// Create and leak 8 Reader's.
for i in 0..8 {
let reader = r.clone();
std::mem::forget(reader);
}
// Now there are 10.
assert_eq!(w.reader_count().get(), 10);
sourcepub fn readers_exist(&self) -> bool
pub fn readers_exist(&self) -> bool
Does a Reader
object associated with this Writer
exist?
As noted in Writer::reader_count
, the Writer
will always
count as a Reader
, meaning the strong count will always at
least be 1
.
If it is 1
, that means no Reader
object exists,
in that case, this function will return false
.
let (r, mut w) = someday::new::<String>("".into());
// 1 `Reader` exists.
assert!(w.readers_exist());
// 0 `Reader`'s (excluding the `Writer`) exist.
drop(r);
assert!(!w.readers_exist());
sourcepub fn status(&self) -> StatusInfo<'_, T>
pub fn status(&self) -> StatusInfo<'_, T>
Get the current status on the Writer
and Reader
This is a bag of various metadata about the current
state of the Writer
and Reader
.
If you only need 1 or a few of the fields in StatusInfo
,
consider using their individual methods instead.
source§impl<T: Clone> Writer<T>
impl<T: Clone> Writer<T>
sourcepub fn push(&mut self) -> PushInfo
pub fn push(&mut self) -> PushInfo
Conditionally push Writer
’s local committed data to the Reader
’s.
This will only push changes if there are new Commit
’s
(i.e if Writer::synced
returns true
).
This may be expensive as there are other operations in this function (memory reclaiming, re-applying patches).
This will return how many Commit
’s the Writer
’s pushed.
Reader
’s will atomically be able to access the
the new Commit
before this function is over.
The Patch
’s that were not commit()
’ed will not be
pushed and will remain in the staged()
vector of patches.
The PushInfo
object returned is just a container
for some metadata about the push()
operation.
let (r, mut w) = someday::new::<String>("".into());
w.add(Patch::Ptr(|w, _| w.push_str("abc")));
// This call does nothing since
// we haven't committed anything.
let push_info = w.push();
assert_eq!(push_info.timestamp, 0);
assert_eq!(push_info.commits, 0);
assert_eq!(push_info.reclaimed, false);
// Now there are commits to push.
w.commit();
if w.ahead() {
let push_info = w.push();
// We pushed 1 commit.
assert_eq!(push_info.timestamp, 1);
assert_eq!(push_info.commits, 1);
assert_eq!(push_info.reclaimed, true);
} else {
// this branch cannot happen
unreachable!();
}
sourcepub fn push_wait(&mut self, duration: Duration) -> PushInfo
pub fn push_wait(&mut self, duration: Duration) -> PushInfo
This function is the same as Writer::push()
but it will std::thread::sleep()
for at least duration
amount of time to wait to reclaim the old Reader
’s data.
If duration
has passed, the Writer
will
clone the data as normal and continue on.
This is useful if you know your Reader
’s only
hold onto old data for a brief moment.
let (r, mut w) = someday::new::<String>("".into());
w.add(Patch::Ptr(|w, _| w.push_str("abc")));
w.commit();
let commit = r.head();
spawn(move || {
// This `Reader` is holding onto the old data.
let moved = commit;
// But will let go after 1 millisecond.
sleep(Duration::from_millis(1));
});
// Wait 250 milliseconds before resorting to cloning data.
let commit_info = w.push_wait(Duration::from_millis(250));
// We pushed 1 commit.
assert_eq!(commit_info.commits, 1);
// And we successfully reclaimed the old data cheaply.
assert_eq!(commit_info.reclaimed, true);
sourcepub fn push_do<F, R>(&mut self, f: F) -> (PushInfo, R)where
F: FnOnce() -> R,
pub fn push_do<F, R>(&mut self, f: F) -> (PushInfo, R)where
F: FnOnce() -> R,
This function is the same as Writer::push()
but it will execute the function F
in the meanwhile before
attempting to reclaim the old Reader
data.
The generic R
is the return value of the function.
Leaving it blank and having a non-returning function will
be enough inference that the return value is ()
.
Basically: “run the function F
while we’re waiting”
This is useful to get some work done before waiting
on the Reader
’s to drop old copies of data.
let (r, mut w) = someday::new::<String>("".into());
let head = r.head();
spawn(move || {
// This `Reader` is holding onto the old data.
let moved = head;
// But will let go after 100 milliseconds.
sleep(Duration::from_millis(100));
});
// Some work to be done.
let mut hashmap = HashMap::<usize, String>::new();
let mut vec = vec![];
// Commit.
// Now the `Writer` is ahead by 1 commit, while
// the `Reader` is hanging onto the old one.
w.add(Patch::Ptr(|w, _| w.push_str("abc")));
w.commit();
// Pass in a closure, so that we can do
// arbitrary things in the meanwhile...!
let (push_info, return_value) = w.push_do(|| {
// While we're waiting, let's get some work done.
// Add a bunch of data to this HashMap.
(0..1_000).for_each(|i| {
hashmap.insert(i, format!("{i}"));
});
// Add some data to the vector.
(0..1_000).for_each(|_| {
vec.push(format!("aaaaaaaaaaaaaaaa"));
}); // <- `push_do()` returns `()`
}); // although we could return anything
// and it would be binded to `return_value`
// At this point, the old `Reader`'s have
// probably all dropped their old references
// and we can probably cheaply reclaim our
// old data back.
// And yes, looks like we got it back cheaply:
assert_eq!(push_info.reclaimed, true);
// And we did some work
// while waiting to get it:
assert_eq!(hashmap.len(), 1_000);
assert_eq!(vec.len(), 1_000);
assert_eq!(return_value, ());
sourcepub fn push_clone(&mut self) -> PushInfo
pub fn push_clone(&mut self) -> PushInfo
This function is the same as Writer::push()
but it will always clone the data
and not attempt to reclaim any old data.
This is useful if you know reclaiming old data and re-applying your commits would take longer and/or be more expensive than cloning the data itself.
Or if you know your Reader
’s will be holding
onto the data for a long time, and reclaiming data
will be unlikely.
let (r, mut w) = someday::new::<String>("".into());
w.add(Patch::Ptr(|w, _| w.push_str("abc")));
w.commit();
let commit = r.head();
spawn(move || {
// This `Reader` will hold onto the old data forever.
let moved = commit;
loop { std::thread::park(); }
});
// Always clone data, don't wait.
let push_info = w.push_clone();
// We pushed 1 commit.
assert_eq!(push_info.commits, 1);
assert_eq!(push_info.reclaimed, false);
source§impl<T: Clone> Writer<T>
impl<T: Clone> Writer<T>
sourcepub fn pull(&mut self) -> Option<PullInfo<T>>
pub fn pull(&mut self) -> Option<PullInfo<T>>
Conditionally overwrite the Writer
’s local Commit
with the current Reader
Commit
If the Writer
and Reader
are Writer::synced()
, this will return None
.
If the Writer
is ahead of the Reader
, this will:
- Discard all
Patch
’s that have been alreadycommit()
’ed - Keep staged
Patch
’s that haven’t beencommit()
- Return
Some(PullInfo)
The PullInfo
object returned is just a container
for some metadata about the pull()
operation.
§Timestamp
If this pull is successful (the Writer
and Reader
aren’t in sync),
this will reset your Writer
’s Timestamp
to whatever your Reader
’s was.
§⚠️ Warning
This overwrites your Writer
’s data!
Like a git pull --force
!
let (r, mut w) = someday::new::<String>("".into());
// Commit local changes.
w.add(Patch::Ptr(|w, _| w.push_str("hello")));
w.commit();
assert_eq!(w.head().data, "hello");
// Reader's sees nothing
assert_eq!(r.head().data, "");
// Pull from the Reader.
let pull_status: PullInfo<String> = w.pull().unwrap();
assert_eq!(pull_status.old_writer_commit.data, "hello");
// We're back to square 1.
assert_eq!(w.head().data, "");
// If we try to pull again, nothing will happen
// since we are already synced with `Reader`s.
assert!(w.pull().is_none());
sourcepub fn overwrite(&mut self, data: T) -> Commit<T>
pub fn overwrite(&mut self, data: T) -> Commit<T>
Overwrite the Writer
’s local data with data
.
The Writer
’s old local data is returned.
All Patch
’s that have been already commit()
’ed are discarded (Writer::committed_patches()
).
Staged Patch
’s that haven’t been commit()
still kept around (Writer::staged()
).
A Patch
that overwrites the data applied with commit()
would be
equivalent to this convenience function, although, this function will
be slightly cheaper as it avoids cloning an extra time.
let (r, mut w) = someday::new::<String>("".into());
// Push changes.
w.add(Patch::Ptr(|w, _| w.push_str("hello")));
w.commit(); // <- commit 1
w.push();
assert_eq!(w.timestamp(), 1);
// Reader's sees them.
assert_eq!(r.head().data, "hello");
assert_eq!(r.head().timestamp, 1);
// Commit some changes.
w.add(Patch::Ptr(|w, _| *w = "hello".into()));
w.commit(); // <- commit 2
w.add(Patch::Ptr(|w, _| *w = "hello".into()));
w.commit(); // <- commit 3
w.add(Patch::Ptr(|w, _| *w = "hello".into()));
w.commit(); // <- commit 4
assert_eq!(w.committed_patches().len(), 3);
// Overwrite the Writer with arbitrary data.
let old_data = w.overwrite(String::from("world")); // <- commit 5
assert_eq!(old_data.data, "hello");
assert_eq!(w.data(), "world");
// Committed functions were deleted, but 1 patch is leftover.
// This is an automatically inserted patch that makes the
// reclaimed `Reader`'s `.clone()` the new data.
assert_eq!(w.committed_patches().len(), 1);
// `Reader`'s still don't see changes.
assert_eq!(r.head().data, "hello");
// Push that change.
w.push();
// Now `Reader`s see change.
assert_eq!(r.head().data, "world");
// 5 commits total.
assert_eq!(w.timestamp(), 5);
assert_eq!(r.head().timestamp, 5);
§Timestamp
This increments the Writer
’s local Timestamp
by 1
.
source§impl<T: Clone> Writer<T>
impl<T: Clone> Writer<T>
sourcepub fn fork(&self) -> Self
pub fn fork(&self) -> Self
Fork off from the current Reader::head
commit and create a Writer
.
This new Writer
:
- will contain no
Patch
’s - is disconnected, meaning it has absolutely no
relation to
self
or any other previousReader
’s. - has the latest
Writer::head
as the base forWriter
andReader
’s
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 off into another `Writer`.
let mut w2 = w.fork();
let r2 = w2.reader();
// It inherits the data of the previous `Writer`.
assert_eq!(w.data(), "hello");
assert_eq!(w.timestamp(), 1);
assert_eq!(w.head().data, "hello");
assert_eq!(w.head().timestamp, 1);
// And has no relation to the previous `Writer/Reader`'s.
assert!(!r.connected(&r2));
assert!(!r.connected_writer(&w2));
w2.add_commit(|s, _| {
s.push_str(" world!");
});
assert_eq!(w2.data(), "hello world!");
assert_eq!(w2.timestamp(), 2);
assert_eq!(w.data(), "hello");
assert_eq!(w.timestamp(), 1);
assert_eq!(r.head().data, "");
assert_eq!(r.head().timestamp, 0);
source§impl<T: Clone> Writer<T>
impl<T: Clone> Writer<T>
sourcepub fn diff(&self) -> boolwhere
T: PartialEq<T>,
pub fn diff(&self) -> boolwhere
T: PartialEq<T>,
If the Writer
’s local Commit
is different than the Reader
’s
Compares the Commit
that the Reader
’s can
currently access with the Writer
’s current local Commit
.
This returns true
if either the:
Timestamp
is different- Data is different
§Purpose
In correct scenarios, the Writer
’s and Reader
’s Timestamp
’s
should be all that is needed to indicate if the data is different or not.
However, if your Patch
functions are non-determistic,
the data may get out of sync.
Thus, this function is mostly meant to be used for debugging purposes.
// Create a non-deterministic `Writer/Reader`
// out-of-sync issue.
static STATE: Mutex<usize> = Mutex::new(1);
let (_, mut w) = someday::new::<usize>(0);
w.add(Patch::boxed(move |w, _| {
let mut state = STATE.lock().unwrap();
*state *= 10; // 1*10 the first time, 10*10 the second time...
*w = *state;
}));
w.commit();
w.push();
// Same timestamps...
assert_eq!(w.timestamp(), w.reader().head().timestamp);
// ⚠️ Out of sync data!
assert_eq!(*w.data(), 100);
assert_eq!(w.reader().head().data, 10);
// But, this function tells us the truth.
assert_eq!(w.diff(), true);
sourcepub fn ahead(&self) -> bool
pub fn ahead(&self) -> bool
If the Writer
’s local Timestamp
is greater than the Reader
’s Timestamp
Compares the timestamp of the Reader
’s currently available
data with the Writer
’s current local timestamp.
This returns true
if the Writer
’s timestamp
is greater than Reader
’s timestamp (which means
Writer
is ahead of the Reader
’s)
Note that this does not check the data itself, only the Timestamp
.
let (r, mut w) = someday::new::<String>("".into());
// Commit 10 times but don't push.
for i in 0..10 {
w.add(Patch::Ptr(|w, _| w.push_str("abc")));
w.commit();
}
// Writer at timestamp 10.
assert_eq!(w.timestamp(), 10);
// Reader at timestamp 0.
assert_eq!(r.head().timestamp, 0);
// Writer is ahead of the Reader's.
assert!(w.ahead());
sourcepub const fn ahead_of(&self, commit: &Commit<T>) -> bool
pub const fn ahead_of(&self, commit: &Commit<T>) -> bool
If the Writer
’s local Timestamp
is greater than an arbitrary Commit
’s Timestamp
This takes any type of Commit
, so either CommitRef
or Commit
can be used as input.
let (_, mut w) = someday::new::<String>("".into());
// Commit 10 times.
for i in 0..10 {
w.add(Patch::Ptr(|w, _| w.push_str("abc")));
w.commit();
}
// At timestamp 10.
assert_eq!(w.timestamp(), 10);
// Create fake `Commit`
let fake_commit = Commit {
timestamp: 1,
data: String::new(),
};
// Writer is ahead of that commit.
assert!(w.ahead_of(&fake_commit));
sourcepub const fn behind(&self, commit: &Commit<T>) -> bool
pub const fn behind(&self, commit: &Commit<T>) -> bool
If the Writer
’s local Timestamp
is less than an arbitrary Commit
’s Timestamp
This takes any type of Commit
, so either CommitRef
or Commit
can be used as input.
let (_, mut w) = someday::new::<String>("".into());
// At timestamp 0.
assert_eq!(w.timestamp(), 0);
// Create fake `Commit`
let fake_commit = Commit {
timestamp: 1000,
data: String::new(),
};
// Writer is behind that commit.
assert!(w.behind(&fake_commit));
sourcepub const fn timestamp(&self) -> Timestamp
pub const fn timestamp(&self) -> Timestamp
Get the current Timestamp
of the Writer
’s local Commit
This returns the number indicating the Writer
’s data’s version.
This number starts at 0
, increments by 1
every time a Writer::commit()
-like operation is called, and it will never be less than the Reader
’s Timestamp
.
let (r, mut w) = someday::new::<String>("".into());
// At timestamp 0.
assert_eq!(w.timestamp(), 0);
// Commit some changes.
w.add(Patch::Ptr(|w, _| w.push_str("abc")));
w.commit();
// At timestamp 1.
assert_eq!(w.timestamp(), 1);
// We haven't pushed, so Reader's
// are still at timestamp 0.
assert_eq!(r.head().timestamp, 0);
sourcepub fn timestamp_remote(&self) -> Timestamp
pub fn timestamp_remote(&self) -> Timestamp
Get the current Timestamp
of the Reader
’s “head” Commit
This returns the number indicating the Reader
’s data’s version.
This will never be greater than the Writer
’s timestamp.
let (r, mut w) = someday::new::<String>("".into());
// At timestamp 0.
assert_eq!(w.timestamp(), 0);
// Commit some changes.
w.add(Patch::Ptr(|w, _| w.push_str("abc")));
w.commit();
// Writer is at timestamp 1.
assert_eq!(w.timestamp(), 1);
// We haven't pushed, so Reader's
// are still at timestamp 0.
assert_eq!(r.head().timestamp, 0);
// Push changes
w.push();
// Readers are now up-to-date.
assert_eq!(r.head().timestamp, 1);
sourcepub fn timestamp_diff(&self) -> usize
pub fn timestamp_diff(&self) -> usize
Get the difference between the Writer
’s and Reader
’s Timestamp
This returns the number indicating how many commits the
Writer
is ahead on compared to the Reader
’s.
In other words, it is: writer_timestamp - reader_timestamp
let (r, mut w) = someday::new::<String>("".into());
// At timestamp 0.
assert_eq!(w.timestamp(), 0);
// Push 1 change.
w.add(Patch::Ptr(|w, _| w.push_str("abc")));
w.commit();
w.push();
// Commit 5 changes locally.
for i in 0..5 {
w.add(Patch::Ptr(|w, _| w.push_str("abc")));
w.commit();
}
// Writer is at timestamp 5.
assert_eq!(w.timestamp(), 6);
// Reader's are still at timestamp 1.
assert_eq!(r.head().timestamp, 1);
// The difference is 5.
assert_eq!(w.timestamp_diff(), 5);
sourcepub fn synced(&self) -> bool
pub fn synced(&self) -> bool
Is the Writer
’s and Reader
’s Timestamp
the same?
This returns true
if the Writer
and Reader
’s timestamp
are the same, indicating they have same data and are in-sync.
let (r, mut w) = someday::new::<String>("".into());
// At timestamp 0.
assert_eq!(w.timestamp(), 0);
// Push 1 change.
w.add(Patch::Ptr(|w, _| w.push_str("abc")));
w.commit();
w.push();
// Commit 5 changes locally.
for i in 0..5 {
w.add(Patch::Ptr(|w, _| w.push_str("abc")));
w.commit();
}
// Writer is at timestamp 5.
assert_eq!(w.timestamp(), 6);
// Reader's are still at timestamp 1.
assert_eq!(r.head().timestamp, 1);
// They aren't in sync.
assert_eq!(w.synced(), false);
// Now they are.
w.push();
assert_eq!(w.synced(), true);
source§impl<T: Clone> Writer<T>
impl<T: Clone> Writer<T>
sourcepub fn new(data: T) -> Self
pub fn new(data: T) -> Self
Same as crate::free::new
but without creating a Reader
.
let (r, w) = someday::new("hello");
let w2 = Writer::new("hello");
assert_eq!(w.data(), w2.data());
assert_eq!(w.timestamp(), w2.timestamp());
sourcepub fn restore(&mut self) -> Drain<'_, Patch<T>>
pub fn restore(&mut self) -> Drain<'_, Patch<T>>
Restore all the staged changes.
This removes all the Patch
’s that haven’t yet been commit()
’ed.
Calling Writer::staged().drain(..)
would be equivalent.
Dropping the std::vec::Drain
will drop the Patch
’s.
let (r, mut w) = someday::new::<String>("".into());
// Add some changes, but don't commit.
w.add(Patch::Ptr(|w, _| w.push_str("abc")));
assert_eq!(w.staged().len(), 1);
// Restore changes.
let drain = w.restore();
assert_eq!(drain.count(), 1);
sourcepub fn shrink_to_fit(&mut self)
pub fn shrink_to_fit(&mut self)
Shrinks the capacity of the Patch
Vec
’s as much as possible
This calls Vec::shrink_to_fit()
on the 2
internal Vec
’s in Writer
holding:
- The currently staged
Patch
’s - The already committed
Patch
’s
let (_, mut w) = someday::new::<String>("".into());
// Capacity is 16.
assert_eq!(w.committed_patches().capacity(), 16);
assert_eq!(w.staged().capacity(), 16);
// Commit 32 `Patch`'s
for i in 0..32 {
w.add(Patch::Ptr(|w, _| *w = "".into()));
w.commit();
}
// Stage 16 `Patch`'s
for i in 0..16 {
w.add(Patch::Ptr(|w, _| *w = "".into()));
}
// Commit capacity is now 32.
assert_eq!(w.committed_patches().capacity(), 32);
// This didn't change, we already had
// enough space to store them.
assert_eq!(w.staged().capacity(), 16);
// Commit, push, shrink.
w.commit();
w.push();
w.shrink_to_fit();
// They're now empty and taking 0 space.
assert_eq!(w.committed_patches().capacity(), 0);
assert_eq!(w.staged().capacity(), 0);
sourcepub fn reserve_exact(&mut self, additional: usize)
pub fn reserve_exact(&mut self, additional: usize)
Reserve capacity in the Patch
Vec
’s
This calls Vec::reserve_exact()
on the 2
internal Vec
’s in Writer
holding:
- The currently staged
Patch
’s - The already committed
Patch
’s
let (_, mut w) = someday::new::<String>("".into());
// Capacity is 16.
assert_eq!(w.committed_patches().capacity(), 16);
assert_eq!(w.staged().capacity(), 16);
// Reserve space for 48 more patches.
w.reserve_exact(48);
assert!(w.committed_patches().capacity() >= 48);
assert!(w.staged().capacity() >= 48);
§Panics
Panics if the new capacity exceeds isize::MAX
bytes.
sourcepub fn connected(&self, reader: &Reader<T>) -> bool
pub fn connected(&self, reader: &Reader<T>) -> bool
Is this Writer
associated with this Reader
?
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!(w.connected(&r));
assert!(w.connected(&r2));
assert!(w.connected(&r3));
// This one is completely separate.
let (r4, _) = someday::new(());
assert!(!r.connected(&r4));
sourcepub fn disconnect(&mut self)
pub fn disconnect(&mut self)
Disconnect from the Reader
’s associated with this Writer
.
This completely severs the link between the
Reader
’s associated with this Writer
.
Any older Reader
’s will no longer receive Commit
’s
from this Writer
, and Reader::writer_dropped
will start
to return true
. From the perspective of the older Reader
’s,
calling this function is the same as this Writer
being dropped.
Any future Reader
’s created after this function
are completely separate from the past Reader
’s.
let (r, mut w) = someday::new("");
// Connected `Reader` <-> `Writer`.
assert!(w.connected(&r));
// Now, disconnected.
w.disconnect();
assert!(!w.connected(&r));
// The older `Reader` won't see pushes anymore.
w.add_commit_push(|w, _| *w = "hello");
assert_eq!(*w.data(), "hello");
assert_eq!(r.head().data, "");
// But, newer `Reader`'s will.
let r2 = w.reader();
assert_eq!(r2.head().data, "hello");
sourcepub fn into_inner(self) -> WriterInfo<T>
pub fn into_inner(self) -> WriterInfo<T>
Consume this Writer
and return the inner components.
let (r, mut w) = someday::new::<String>("".into());
// Commit some changes.
w.add(Patch::Ptr(|w, _| w.push_str("a")));
w.commit();
// Add but don't commit.
w.add(Patch::Ptr(|w, _| w.push_str("b")));
let WriterInfo {
writer,
reader,
staged,
committed_patches,
} = w.into_inner();
assert_eq!(writer.data, "a");
assert_eq!(reader.data, ""); // We never `push()`'ed, so Readers saw nothing.
assert_eq!(staged.len(), 1);
assert_eq!(committed_patches.len(), 1);
Trait Implementations§
source§impl<T> BorshDeserialize for Writer<T>where
T: Clone + BorshDeserialize,
impl<T> BorshDeserialize for Writer<T>where
T: Clone + BorshDeserialize,
source§fn deserialize_reader<R: Read>(reader: &mut R) -> Result<Self>
fn deserialize_reader<R: Read>(reader: &mut R) -> Result<Self>
This will deserialize a Commit
directly into a Writer
.
let (r, mut w) = someday::new(String::from("hello"));
w.add_commit(|w, _| {
w.push_str(" world!");
});
assert_eq!(w.timestamp(), 1);
assert_eq!(w.data(), "hello world!");
assert_eq!(r.head().timestamp, 0);
assert_eq!(r.head().data, "hello");
// Decode into a `Commit`.
let encoded = borsh::to_vec(&w).unwrap();
let decoded: Commit<String> = borsh::from_slice(&encoded).unwrap();
assert_eq!(decoded, Commit { timestamp: 1, data: String::from("hello world!") });
// Decode directly into a `Writer<T>`.
let writer: Writer<String> = borsh::from_slice(&encoded).unwrap();
assert_eq!(writer.timestamp(), 1);
assert_eq!(writer.data(), "hello world!");
source§fn deserialize(buf: &mut &[u8]) -> Result<Self, Error>
fn deserialize(buf: &mut &[u8]) -> Result<Self, Error>
source§fn try_from_slice(v: &[u8]) -> Result<Self, Error>
fn try_from_slice(v: &[u8]) -> Result<Self, Error>
fn try_from_reader<R>(reader: &mut R) -> Result<Self, Error>where
R: Read,
source§impl<T> BorshSerialize for Writer<T>where
T: Clone + BorshSerialize,
impl<T> BorshSerialize for Writer<T>where
T: Clone + BorshSerialize,
source§impl<T: Clone> Clone for Writer<T>
impl<T: Clone> Clone for Writer<T>
source§fn clone(&self) -> Self
fn clone(&self) -> Self
This is the exact same as Writer::fork
.
Note that this means cloning a Writer
completely
disconnects it from previous Reader
’s.
This does not create 2 Writer
’s to the same data,
as that is not allowed.
let (r, mut w) = someday::new(String::new());
// The clone has no relation to the previous `Writer/Reader`'s.
let clone: Writer<String> = w.clone();
assert!(!clone.connected(&r));
// Wrapping `Writer` in a shared mutual exclusion primitive
// allows it to be cheaply cloned, without `fork()`-like behavior.
let shared = Arc::new(Mutex::new(clone));
let reader = shared.lock().unwrap().reader();
assert!(shared.lock().unwrap().connected(&reader));
assert!(!shared.lock().unwrap().connected(&r));
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moresource§impl<T> Decode for Writer<T>
impl<T> Decode for Writer<T>
source§fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError>
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError>
This will deserialize a Commit
directly into a Writer
.
let (r, mut w) = someday::new(String::from("hello"));
w.add_commit(|w, _| {
w.push_str(" world!");
});
assert_eq!(w.timestamp(), 1);
assert_eq!(w.data(), "hello world!");
assert_eq!(r.head().timestamp, 0);
assert_eq!(r.head().data, "hello");
let config = bincode::config::standard();
// Decode into a `Commit`.
let encoded = bincode::encode_to_vec(&w, config).unwrap();
let decoded: Commit<String> = bincode::decode_from_slice(&encoded, config).unwrap().0;
assert_eq!(decoded, Commit { timestamp: 1, data: String::from("hello world!") });
// Decode directly into a `Writer<T>`.
let writer: Writer<String> = bincode::decode_from_slice(&encoded, config).unwrap().0;
assert_eq!(writer.timestamp(), 1);
assert_eq!(writer.data(), "hello world!");
source§impl<T> Default for Writer<T>
impl<T> Default for Writer<T>
source§fn default() -> Self
fn default() -> Self
Only generates the Writer
.
This initializes your data T
with Default::default()
.
let (_, w1) = someday::new::<usize>(Default::default());
let w2 = Writer::<usize>::default();
assert_eq!(*w1.data(), 0);
assert_eq!(*w2.data(), 0);
source§impl<'de, T> Deserialize<'de> for Writer<T>where
T: Clone + Deserialize<'de>,
impl<'de, T> Deserialize<'de> for Writer<T>where
T: Clone + Deserialize<'de>,
source§fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
This will deserialize a Commit
directly into a Writer
.
let (r, mut w) = someday::new(String::from("hello"));
w.add_commit(|w, _| {
w.push_str(" world!");
});
assert_eq!(w.timestamp(), 1);
assert_eq!(w.data(), "hello world!");
assert_eq!(r.head().timestamp, 0);
assert_eq!(r.head().data, "hello");
let json = serde_json::to_string(&w).unwrap();
assert_eq!(json, "{\"timestamp\":1,\"data\":\"hello world!\"}");
let writer: Writer<String> = serde_json::from_str(&json).unwrap();
assert_eq!(writer.timestamp(), 1);
assert_eq!(writer.data(), "hello world!");
source§impl<T: Clone> From<T> for Writer<T>
impl<T: Clone> From<T> for Writer<T>
source§fn from(data: T) -> Self
fn from(data: T) -> Self
Same as crate::free::new
but without creating a Reader
.
Auto Trait Implementations§
impl<T> !RefUnwindSafe for Writer<T>
impl<T> Send for Writer<T>
impl<T> !Sync for Writer<T>
impl<T> Unpin for Writer<T>where
T: Unpin,
impl<T> !UnwindSafe for Writer<T>
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T, A> DynAccess<T> for A
impl<T, A> DynAccess<T> for A
source§fn load(&self) -> DynGuard<T>
fn load(&self) -> DynGuard<T>
Access::load
.