1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
//! `Writer<T>`
//---------------------------------------------------------------------------------------------------- Use
use std::sync::Arc;
use crate::{
writer::token::WriterToken,
writer::Writer,
patch::Patch,
reader::Reader,
commit::Commit,
info::WriterInfo,
};
#[allow(unused_imports)] // docs
// use crate::Commit;
//---------------------------------------------------------------------------------------------------- Writer
impl<T: Clone> Writer<T> {
/// Same as [`crate::free::new`] but without creating a [`Reader`].
///
/// ```rust
/// # use someday::*;
/// let (r, w) = someday::new("hello");
/// let w2 = Writer::new("hello");
///
/// assert_eq!(w.data(), w2.data());
/// assert_eq!(w.timestamp(), w2.timestamp());
/// ```
pub fn new(data: T) -> Self {
crate::free::new_inner(Commit { data, timestamp: 0 })
}
#[inline]
#[allow(clippy::type_complexity)]
/// Restore all the staged changes.
///
/// This removes all the `Patch`'s that haven't yet been [`commit()`](Writer::commit)'ed.
///
/// Calling `Writer::staged().drain(..)` would be equivalent.
///
/// Dropping the [`std::vec::Drain`] will drop the `Patch`'s.
///
/// ```rust
/// # use someday::*;
/// 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);
/// ```
pub fn restore(&mut self) -> std::vec::Drain<'_, Patch<T>> {
self.patches.drain(..)
}
/// 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:
/// 1. The currently staged `Patch`'s
/// 2. The already committed `Patch`'s
///
/// ```rust
/// # use someday::*;
/// # use std::{thread::*,time::*};
/// 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);
/// ```
pub fn shrink_to_fit(&mut self) {
self.patches.shrink_to_fit();
self.patches_old.shrink_to_fit();
}
/// Reserve capacity in the `Patch` [`Vec`]'s
///
/// This calls [`Vec::reserve_exact()`] on the 2
/// internal `Vec`'s in [`Writer`] holding:
/// 1. The currently staged `Patch`'s
/// 2. The already committed `Patch`'s
///
/// ```rust
/// # use someday::*;
/// # use std::{thread::*,time::*};
/// 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.
pub fn reserve_exact(&mut self, additional: usize) {
self.patches.reserve_exact(additional);
self.patches_old.reserve_exact(additional);
}
/// 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`].
///
/// ```rust
/// # use someday::*;
/// 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));
/// ```
pub fn connected(&self, reader: &Reader<T>) -> bool {
Arc::ptr_eq(&self.arc, &reader.arc)
}
/// 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.
///
/// ```rust
/// # use someday::*;
/// 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");
/// ```
pub fn disconnect(&mut self) {
self.token = WriterToken::new();
self.arc = Arc::new(arc_swap::ArcSwap::new(Arc::clone(&self.remote)));
}
#[allow(clippy::missing_panics_doc, clippy::type_complexity)]
/// Consume this [`Writer`] and return the inner components.
///
/// ```rust
/// # use someday::*;
/// # use std::{thread::*,time::*};
/// 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);
/// ```
pub fn into_inner(self) -> WriterInfo<T> {
WriterInfo {
// INVARIANT: local must be initialized after push()
writer: self.local.unwrap(),
reader: self.remote,
staged: self.patches,
committed_patches: self.patches_old,
}
}
}