snaplog/scoped/
mod.rs

1//! A scoped [`ScopedSnaplog`][Snaplog] and it's associated types. A `ScopedSnaplog` is used to
2//! record snapshots of changes to only part of a value, such as successive edits to a file's name
3//! without editing it's ancestors.
4//!
5//! To scope a type, implement [`IntoScoped`], a trait to denote how to deconstruct and reconstruct
6//! the type, the `ScopedSnaplog` takes care of the rest.
7//!
8//! # Examples
9//! All examples in this module assume this type is given.
10//!
11//! Given a type like this:
12//! ```
13//! use snaplog::scoped::IntoScoped;
14//!
15//! #[derive(Debug, PartialEq)]
16//! pub struct Prefixed {
17//!     pub prefix: Option<&'static str>,
18//!     pub content: &'static str,
19//! }
20//!
21//! impl Prefixed {
22//!     pub fn new(s: &'static str) -> Self {
23//!         let parts = s.split_once(':');
24//!
25//!         Self {
26//!             prefix: parts.map(|(p, _)| p),
27//!             content: parts.map(|(_, c)| c).unwrap_or(s),
28//!         }
29//!     }
30//! }
31//!
32//! impl IntoScoped for Prefixed {
33//!     type Scope = &'static str;
34//!     type Ignored = Option<&'static str>;
35//!
36//!     fn into_scoped(self) -> (Self::Scope, Self::Ignored) {
37//!         (self.content, self.prefix)
38//!     }
39//!
40//!     fn from_scoped(scope: Self::Scope, ignored: Self::Ignored) -> Self {
41//!         Self {
42//!             prefix: ignored,
43//!             content: scope,
44//!         }
45//!     }
46//! }
47//! ```
48//!
49//! You can use the [`Snaplog`] like this:
50//! ```
51//! # use snaplog::{Select, scoped::{Snaplog, __Prefixed as Prefixed}};
52//! let mut snaplog = Snaplog::new(Prefixed::new("prefix:content"));
53//! assert_eq!(snaplog.has_changes(), false);
54//!
55//! snaplog.record_change(|prev| { assert_eq!(prev, &"content"); "content-copy" });
56//! snaplog.record_change(|prev| { assert_eq!(prev, &"content-copy"); "new" });
57//! assert_eq!(snaplog.has_changes(), true);
58//!
59//! assert_eq!(snaplog[Select::Initial], "content");
60//! assert_eq!(snaplog[Select::At(1)],   "content-copy");
61//! assert_eq!(snaplog[Select::Current], "new");
62//!
63//! snaplog.clear_history();
64//!
65//! assert_eq!(snaplog.history(), ["new"]);
66//! assert_eq!(snaplog.has_changes(), false);
67//! # Ok::<_, Box<dyn std::error::Error>>(())
68//! ```
69//!
70//! And when all changes are done you can simply recombine the parts:
71//! ```
72//! # use snaplog::{Select, scoped::{Snaplog, __Prefixed as Prefixed}};
73//! # let mut snaplog = Snaplog::new(Prefixed::new("prefix:content"));
74//! # snaplog.record("content-copy");
75//! # snaplog.record("new");
76//! assert_eq!(snaplog.into_current(), Prefixed::new("prefix:new"));
77//! ```
78
79use crate::full;
80use crate::{EmptyHistoryError, Select};
81
82use std::collections::TryReserveError;
83use std::ops::RangeBounds;
84
85mod docs_impl;
86
87#[doc(hidden)]
88pub use docs_impl::__Prefixed;
89
90/// A trait for types that can be scoped into parts to apply changes only partially. See
91/// [`ScopedSnaplog`][Snaplog] for examples.
92pub trait IntoScoped {
93    /// The type of the scope that is used when applying changes.
94    type Scope;
95
96    /// The type of the part that is ignored when applying changes.
97    type Ignored;
98
99    /// Separates `Self` into it's scoped and ignored part.
100    fn into_scoped(self) -> (Self::Scope, Self::Ignored);
101
102    /// Creates `Self` from it's scope and ignored part.
103    fn from_scoped(scope: Self::Scope, ignored: Self::Ignored) -> Self;
104}
105
106/// A trait for [`T: IntoScoped`][IntoScoped] that can create thin immutable reference wrappers from
107/// references to their parts which behave like a reference to `Self`.
108///
109/// This trait has correctness requirements similar to [`Borrow`][0], if a trait like [`Eq`],
110/// [`Ord`] or [`Hash`] is implemented for `T`, then the same conditions formulated by `Borrow` must
111/// hold.
112///
113/// [0]: std::borrow::Borrow
114pub trait AsThinScoped: IntoScoped {
115    /// An immutable thin reference type that behaves like `&Self`.
116    type ThinScoped<'this>;
117
118    /// Creates [`Self::ThinScoped`] from references to it's scope and ignored part.
119    fn as_thin_scoped<'a>(
120        scope: &'a Self::Scope,
121        ignored: &'a Self::Ignored,
122    ) -> Self::ThinScoped<'a>;
123}
124
125/// A trait for [`T: IntoScoped`][IntoScoped] that can create thin mutable reference wrappers from
126/// mutable references to their parts which behave like a reference to `Self`.
127///
128/// This trait has correctness requirements similar to [`BorrowMut`][0], if a trait like [`Eq`],
129/// [`Ord`] or [`Hash`] is implemented for `T`, then the same conditions formulated by `BorrowMut`
130/// must hold.
131///
132/// [0]: std::borrow::BorrowMut
133pub trait AsThinScopedMut: AsThinScoped {
134    /// A mutable thin reference type that behaves like `&mut Self`.
135    type ThinScopedMut<'this>;
136
137    /// Creates [`Self::ThinScopedMut`] from mutable references to it's scope and ignored part.
138    fn as_thin_scoped_mut<'a>(
139        scope: &'a mut Self::Scope,
140        ignored: &'a mut Self::Ignored,
141    ) -> Self::ThinScopedMut<'a>;
142}
143
144/// A [`Snaplog`][full] that is scoped to only part of of a type.
145///
146/// # Examples
147/// ```
148/// # use snaplog::{Select, scoped::{Snaplog, __Prefixed as Prefixed}};
149/// let mut snaplog = Snaplog::new(Prefixed::new("prefix:content"));
150/// assert_eq!(snaplog.has_changes(), false);
151///
152/// snaplog.record_change(|prev| { assert_eq!(prev, &"content"); "content-copy" });
153/// snaplog.record_change(|prev| { assert_eq!(prev, &"content-copy"); "new" });
154/// assert_eq!(snaplog.has_changes(), true);
155///
156/// assert_eq!(snaplog[Select::Initial], "content");
157/// assert_eq!(snaplog[Select::At(1)],   "content-copy");
158/// assert_eq!(snaplog[Select::Current], "new");
159///
160/// snaplog.clear_history();
161///
162/// assert_eq!(snaplog.history(), ["new"]);
163/// assert_eq!(snaplog.has_changes(), false);
164/// # Ok::<_, Box<dyn std::error::Error>>(())
165/// ```
166///
167/// [full]: full::Snaplog
168#[derive(Debug, PartialEq, Eq)]
169pub struct Snaplog<T: IntoScoped> {
170    full: full::Snaplog<T::Scope>,
171    ignored: T::Ignored,
172}
173
174/// Various constructor functions.
175impl<T: IntoScoped> Snaplog<T> {
176    /// Creates a new [`Snaplog`] from the given `initial` snapshot with no recorded changes.
177    ///
178    /// # Examples
179    /// ```
180    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
181    /// let snaplog = Snaplog::new(Prefixed::new("prefix:content"));
182    ///
183    /// assert_eq!(snaplog.initial(), &"content");
184    /// assert_eq!(snaplog.ignored(), &Some("prefix"));
185    /// assert_eq!(snaplog.has_changes(), false);
186    /// ```
187    pub fn new(initial: T) -> Self {
188        let (scope, ignored) = initial.into_scoped();
189
190        Self {
191            full: full::Snaplog::new(scope),
192            ignored,
193        }
194    }
195
196    /// Creates a new [`Snaplog`] for the given `history` backing vector.
197    ///
198    /// # Errors
199    /// Returns an error if `history` was empty.
200    ///
201    /// # Examples
202    /// ```
203    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
204    /// assert!(Snaplog::<Prefixed>::try_from_vec(vec!["content"], None).is_ok());
205    /// assert!(Snaplog::<Prefixed>::try_from_vec(vec![], Some("prefix")).is_err());
206    /// ```
207    pub fn try_from_vec(
208        history: Vec<T::Scope>,
209        ignored: T::Ignored,
210    ) -> Result<Self, EmptyHistoryError> {
211        Ok(Self {
212            full: full::Snaplog::try_from_vec(history)?,
213            ignored,
214        })
215    }
216
217    /// Creates a new [`Snaplog`] for the given `history` backing vector.
218    ///
219    /// # Panics
220    /// Panics if `history` was empty.
221    ///
222    /// # Examples
223    /// ```
224    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
225    /// let snaplog: Snaplog<Prefixed> = Snaplog::from_vec(vec![""], None);
226    /// ```
227    ///
228    /// This panics:
229    /// ```should_panic
230    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
231    /// let snaplog: Snaplog<Prefixed> = Snaplog::from_vec(vec![], Some("Prefix"));
232    /// ```
233    pub fn from_vec(history: Vec<T::Scope>, ignored: T::Ignored) -> Self {
234        match Self::try_from_vec(history, ignored) {
235            Ok(this) => this,
236            Err(_) => panic!("history must not be empty"),
237        }
238    }
239
240    /// Creates a new [`Snaplog`] from the given `history`. The elements are collected into a
241    /// [`Vec`] the if you already have a vec at hand use [`from_vec`][Self::try_from_vec]. The
242    /// first element is used as the initial element.
243    ///
244    /// # Errors
245    /// Returns an error if `history` was empty.
246    ///
247    /// # Examples
248    /// ```
249    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
250    /// assert!(Snaplog::<Prefixed>::try_from_history(["a", "b", "c"], None).is_ok());
251    /// assert!(Snaplog::<Prefixed>::try_from_history(std::iter::empty(), Some("a")).is_err());
252    /// ```
253    pub fn try_from_history<I>(history: I, ignored: T::Ignored) -> Result<Self, EmptyHistoryError>
254    where
255        I: IntoIterator<Item = T::Scope>,
256    {
257        Self::try_from_vec(history.into_iter().collect(), ignored)
258    }
259
260    /// Creates a new [`Snaplog`] from the given `history`. The elements are collected into a
261    /// [`Vec`] the if you already have a vec at hand use [`from_vec`][Self::from_vec]. The first
262    /// element is used as the initial element.
263    ///
264    /// # Panics
265    /// Panics if `history` was empty.
266    ///
267    /// # Examples
268    /// ```
269    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
270    /// let snaplog: Snaplog<Prefixed> = Snaplog::from_history(["a", "b", "c"], None);
271    /// ```
272    ///
273    /// This panics:
274    /// ```should_panic
275    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
276    /// let snaplog: Snaplog<Prefixed> = Snaplog::from_history(std::iter::empty(), Some("prefix"));
277    /// ```
278    pub fn from_history<I>(history: I, ignored: T::Ignored) -> Self
279    where
280        I: IntoIterator<Item = T::Scope>,
281    {
282        Self::from_vec(history.into_iter().collect(), ignored)
283    }
284}
285
286/// First class [`Snaplog`] members.
287impl<T: IntoScoped> Snaplog<T> {
288    /// Returns a reference to the internal [`Snaplog`].
289    ///
290    /// # Examples
291    /// ```
292    /// # use snaplog::{full, scoped::{Snaplog, __Prefixed as Prefixed}};
293    /// let snaplog = Snaplog::new(Prefixed::new("prefix:content"));
294    ///
295    /// assert_eq!(snaplog.scope(), &full::Snaplog::new("content"));
296    /// ```
297    pub fn scope(&self) -> &full::Snaplog<T::Scope> {
298        &self.full
299    }
300
301    /// Returns a mutable reference to the internal [`full::Snaplog`].
302    ///
303    /// # Examples
304    /// ```
305    /// # use snaplog::{full, scoped::{Snaplog, __Prefixed as Prefixed}};
306    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:content"));
307    ///
308    /// assert_eq!(snaplog.scope(), &mut full::Snaplog::new("content"));
309    /// ```
310    pub fn scope_mut(&mut self) -> &mut full::Snaplog<T::Scope> {
311        &mut self.full
312    }
313
314    /// Returns a reference to the ignored part of this [`Snaplog`].
315    ///
316    /// # Examples
317    /// ```
318    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
319    /// let snaplog = Snaplog::new(Prefixed::new("prefix:content"));
320    ///
321    /// assert_eq!(snaplog.ignored(), &Some("prefix"));
322    /// ```
323    pub fn ignored(&self) -> &T::Ignored {
324        &self.ignored
325    }
326
327    /// Returns a mutable reference to the internal [`full::Snaplog`].
328    ///
329    /// # Examples
330    /// ```
331    /// # use snaplog::{full, scoped::{Snaplog, __Prefixed as Prefixed}};
332    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:content"));
333    ///
334    /// assert_eq!(snaplog.into_scope(), full::Snaplog::new("content"));
335    /// ```
336    pub fn into_scope(self) -> full::Snaplog<T::Scope> {
337        self.full
338    }
339}
340
341/// Implementations similar to [`full::Snaplog`].
342impl<T: IntoScoped> Snaplog<T> {
343    /// Records a snapshot in this [`Snaplog`].
344    ///
345    /// # Examples
346    /// ```
347    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
348    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
349    ///
350    /// snaplog.record("b");
351    /// snaplog.record("c");
352    /// assert_eq!(snaplog.history(), ["a", "b", "c"]);
353    /// ```
354    pub fn record(&mut self, snapshot: T::Scope) {
355        self.full.record(snapshot);
356    }
357
358    /// Records multiple snapshots in this [`Snaplog`].
359    ///
360    /// # Examples
361    /// ```
362    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
363    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
364    ///
365    /// snaplog.record_all(["b", "c", "d"]);
366    /// assert_eq!(snaplog.history(), ["a", "b", "c", "d"]);
367    /// ```
368    pub fn record_all<I>(&mut self, snapshots: I)
369    where
370        I: IntoIterator<Item = T::Scope>,
371    {
372        self.full.record_all(snapshots);
373    }
374
375    /// Records a change to the current element in this [`Snaplog`].
376    ///
377    /// # Examples
378    /// ```
379    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
380    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
381    ///
382    /// snaplog.record_change(|prev| { assert_eq!(prev, &"a"); "b" });
383    /// snaplog.record_change(|prev| { assert_eq!(prev, &"b"); "c" });
384    /// assert_eq!(snaplog.history(), ["a", "b", "c"]);
385    /// ```
386    pub fn record_change<F>(&mut self, f: F)
387    where
388        F: FnMut(&T::Scope) -> T::Scope,
389    {
390        self.full.record_change(f)
391    }
392
393    /// Records a change to the current element in this [`Snaplog`].
394    ///
395    /// # Errors
396    /// Returns the inner error if the closure failed.
397    ///
398    /// # Examples
399    /// ```
400    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
401    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
402    ///
403    /// snaplog.try_record_change(|prev| { assert_eq!(prev, &"a"); Ok("b") })?;
404    /// snaplog.try_record_change(|prev| { assert_eq!(prev, &"b"); Ok("c") })?;
405    /// assert_eq!(snaplog.try_record_change(|prev| Err(())), Err(()));
406    /// assert_eq!(snaplog.history(), ["a", "b", "c"]);
407    /// # Ok::<_, ()>(())
408    /// ```
409    pub fn try_record_change<F, E>(&mut self, f: F) -> Result<(), E>
410    where
411        F: FnMut(&T::Scope) -> Result<T::Scope, E>,
412    {
413        self.full.try_record_change(f)
414    }
415
416    /// Records multiple successive changes to the current element in this [`Snaplog`].
417    ///
418    /// # Examples
419    /// ```
420    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
421    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
422    ///
423    /// snaplog.record_changes_all(&mut ["b", "c", "d"], |change, _| *change);
424    /// assert_eq!(snaplog.history(), ["a", "b", "c", "d"]);
425    /// ```
426    pub fn record_changes_all<F, M>(&mut self, mutations: &mut [M], f: F)
427    where
428        F: FnMut(&mut M, &T::Scope) -> T::Scope,
429    {
430        self.full.record_changes_all(mutations, f);
431    }
432
433    /// Returns whether or not there are any changes recorded in this [`Snaplog`].
434    ///
435    /// # Examples
436    /// ```
437    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
438    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
439    ///
440    /// assert_eq!(snaplog.has_changes(), false);
441    /// snaplog.record("b");
442    /// snaplog.record("c");
443    /// assert_eq!(snaplog.has_changes(), true);
444    /// ```
445    pub fn has_changes(&self) -> bool {
446        self.full.has_changes()
447    }
448
449    /// Returns the initial element.
450    ///
451    /// # Examples
452    /// ```
453    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
454    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
455    ///
456    /// snaplog.record("b");
457    /// snaplog.record("c");
458    /// assert_eq!(snaplog.initial(), &"a");
459    /// ```
460    pub fn initial(&self) -> &T::Scope {
461        self.full.initial()
462    }
463
464    /// Returns the element at the given [`Select`].
465    ///
466    /// # Examples
467    /// ```
468    /// # use snaplog::{Select, scoped::{Snaplog, __Prefixed as Prefixed}};
469    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
470    ///
471    /// snaplog.record("b");
472    /// snaplog.record("c");
473    /// assert_eq!(snaplog.snapshot_at(Select::At(1)), &"b");
474    /// ```
475    pub fn snapshot_at(&self, select: Select) -> &T::Scope {
476        self.full.snapshot_at(select)
477    }
478
479    /// Returns the current element, that is the last recorded change or the initial element if
480    /// there are no none.
481    ///
482    /// # Examples
483    /// ```
484    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
485    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
486    ///
487    /// snaplog.record("b");
488    /// snaplog.record("c");
489    /// assert_eq!(snaplog.current(), &"c");
490    /// ```
491    pub fn current(&self) -> &T::Scope {
492        self.full.current()
493    }
494
495    /// Returns the initial element.
496    ///
497    /// # Examples
498    /// ```
499    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
500    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
501    ///
502    /// snaplog.record("b");
503    /// snaplog.record("c");
504    /// assert_eq!(snaplog.initial_mut(), &mut "a");
505    /// ```
506    pub fn initial_mut(&mut self) -> &mut T::Scope {
507        self.full.initial_mut()
508    }
509
510    /// Returns the element at the given [`Select`].
511    ///
512    /// # Examples
513    /// ```
514    /// # use snaplog::{Select, scoped::{Snaplog, __Prefixed as Prefixed}};
515    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
516    ///
517    /// snaplog.record("b");
518    /// snaplog.record("c");
519    /// assert_eq!(snaplog.snapshot_at_mut(Select::At(1)), &mut "b");
520    /// ```
521    pub fn snapshot_at_mut(&mut self, select: Select) -> &mut T::Scope {
522        self.full.snapshot_at_mut(select)
523    }
524
525    /// Returns the current element, that is the last recorded change or the initial element if
526    /// there are no none.
527    ///
528    /// # Examples
529    /// ```
530    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
531    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
532    ///
533    /// snaplog.record("b");
534    /// snaplog.record("c");
535    /// assert_eq!(snaplog.current_mut(), &mut "c");
536    /// ```
537    pub fn current_mut(&mut self) -> &mut T::Scope {
538        self.full.current_mut()
539    }
540
541    /// Clones the element at the given [`Select`].
542    ///
543    /// # Examples
544    /// ```
545    /// # use snaplog::{scoped::{Snaplog, __Prefixed as Prefixed}, Select};
546    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
547    ///
548    /// snaplog.record("b");
549    /// snaplog.record("c");
550    /// assert_eq!(snaplog.clone_snapshot_at(Select::At(1)), Prefixed::new("prefix:b"));
551    /// ```
552    pub fn clone_snapshot_at(&self, select: Select) -> T
553    where
554        T::Scope: Clone,
555        T::Ignored: Clone,
556    {
557        // TODO: let the user decide how to reconstruct from references? breaks IntoScoped interface
558        T::from_scoped(self.snapshot_at(select).clone(), self.ignored.clone())
559    }
560
561    /// Returns the full history recorded in this [`Snaplog`], including the initial element.
562    ///
563    /// # Examples
564    /// ```
565    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
566    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
567    ///
568    /// snaplog.record("b");
569    /// snaplog.record("c");
570    /// assert_eq!(snaplog.history(), ["a", "b", "c"]);
571    /// ```
572    pub fn history(&self) -> &[T::Scope] {
573        self.full.history()
574    }
575
576    /// Returns a mutable reference to the underlying `history`.
577    ///
578    /// # Examples
579    /// ```
580    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
581    /// let mut snaplog: Snaplog<Prefixed> = Snaplog::try_from_history(
582    ///     ["a", "b", "c", "d", "e"],
583    ///     None,
584    /// )?;
585    /// let history = snaplog.history_mut();
586    ///
587    /// history[0] = "g";
588    /// assert_eq!(snaplog.history(), ["g", "b", "c", "d", "e"]);
589    /// # Ok::<_, Box<dyn std::error::Error>>(())
590    /// ```
591    pub fn history_mut(&mut self) -> &mut [T::Scope] {
592        self.full.history_mut()
593    }
594
595    /// Drains the history in the specified range, a left open range is interpreted as starting
596    /// behind the initial element, elements that are not yielded from the [`Iterator`] are dropped.
597    ///
598    /// # Panics
599    /// Panics if the lower range bound is inclusive `0`.
600    /// Panics if the lower or upper bound are out of range.
601    ///
602    /// # Examples
603    /// ```
604    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
605    /// let mut snaplog: Snaplog<Prefixed> = Snaplog::try_from_history(
606    ///     ["a", "b", "c", "d", "e"],
607    ///     None,
608    /// )?;
609    ///
610    /// snaplog.drain(2..=3);
611    /// assert_eq!(snaplog.history(), ["a", "b", "e"]);
612    /// # Ok::<_, Box<dyn std::error::Error>>(())
613    /// ```
614    /// The unbounded range is reinterpreted as starting at `1`:
615    /// ```
616    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
617    /// # let mut snaplog: Snaplog<Prefixed> = Snaplog::try_from_history(["a", "b", "c", "d", "e"],
618    /// # None)?;
619    /// snaplog.drain(..);
620    /// assert_eq!(snaplog.history(), ["a"]);
621    /// # Ok::<_, Box<dyn std::error::Error>>(())
622    /// ```
623    /// The only invalid lower bound is `0`:
624    /// ```should_panic
625    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
626    /// # let mut snaplog: Snaplog<Prefixed> = Snaplog::try_from_history(["a", "b", "c", "d", "e"],
627    /// # None)?;
628    /// snaplog.drain(0..);
629    /// # Ok::<_, Box<dyn std::error::Error>>(())
630    /// ```
631    pub fn drain<'r, R>(&'r mut self, range: R) -> impl Iterator<Item = T::Scope> + 'r
632    where
633        R: RangeBounds<usize> + 'r,
634    {
635        self.full.drain(range)
636    }
637
638    /// Wipe the recorded history, keeping only the current element as the new initial element.
639    ///
640    /// # Examples
641    /// ```
642    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
643    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
644    ///
645    /// snaplog.record("b");
646    /// snaplog.record("c");
647    /// snaplog.clear_history();
648    /// assert_eq!(snaplog.initial(), &"c");
649    /// assert_eq!(snaplog.has_changes(), false);
650    /// ```
651    pub fn clear_history(&mut self) {
652        self.full.clear_history();
653    }
654
655    /// Wipe the recorded changes, keeping only the initial element.
656    ///
657    /// # Examples
658    /// ```
659    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
660    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
661    ///
662    /// snaplog.record("b");
663    /// snaplog.record("c");
664    /// snaplog.reset();
665    /// assert_eq!(snaplog.initial(), &"a");
666    /// assert_eq!(snaplog.has_changes(), false);
667    /// ```
668    pub fn reset(&mut self) {
669        self.full.reset();
670    }
671
672    /// Reserve space for `n` additional elements.
673    ///
674    /// # Examples
675    /// ```
676    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
677    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
678    /// snaplog.reserve(10);
679    /// ```
680    pub fn reserve(&mut self, n: usize) {
681        self.full.reserve(n);
682    }
683
684    /// Reserve space for `n` additional elements.
685    ///
686    /// # Errors
687    /// Returns an error if [`Vec::try_reserve`] failed.
688    ///
689    /// # Examples
690    /// ```
691    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
692    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
693    /// snaplog.try_reserve(10)?;
694    /// # Ok::<_, Box<dyn std::error::Error>>(())
695    /// ```
696    pub fn try_reserve(&mut self, n: usize) -> Result<(), TryReserveError> {
697        self.full.try_reserve(n)
698    }
699
700    /// Returns an iterator over references of the whole underling history.
701    ///
702    /// # Examples
703    /// ```
704    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
705    /// let mut snaplog: Snaplog<Prefixed> = Snaplog::try_from_history(
706    ///     ["a", "b", "c", "d", "e"],
707    ///     None,
708    /// )?;
709    ///
710    /// let mut copy = vec![];
711    /// for (snapshot, _) in snaplog.iter() {
712    ///     copy.push(*snapshot);
713    /// }
714    ///
715    /// assert_eq!(copy, ["a", "b", "c", "d", "e"]);
716    /// # Ok::<_, Box<dyn std::error::Error>>(())
717    /// ```
718    pub fn iter(&self) -> Iter<'_, T> {
719        self.into_iter()
720    }
721
722    /// Returns an iterator over mutable references of the whole underling history.
723    ///
724    /// # Examples
725    /// ```
726    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
727    /// let mut snaplog: Snaplog<Prefixed> = Snaplog::try_from_history(
728    ///     ["a", "b", "c", "d", "e"],
729    ///     None,
730    /// )?;
731    ///
732    /// for (snapshot, _) in snaplog.iter_mut().filter(|&(&mut s, _)| s == "a" || s == "d") {
733    ///     *snapshot = "f";
734    /// }
735    ///
736    /// assert_eq!(snaplog.history(), ["f", "b", "c", "f", "e"]);
737    /// # Ok::<_, Box<dyn std::error::Error>>(())
738    /// ```
739    pub fn iter_mut(&mut self) -> IterMut<'_, T> {
740        self.into_iter()
741    }
742
743    /// Unwrap the [`Snaplog`] into it's initial snapshot.
744    ///
745    /// # Examples
746    /// ```
747    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
748    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
749    ///
750    /// snaplog.record("b");
751    /// snaplog.record("c");
752    /// assert_eq!(snaplog.into_initial(), Prefixed::new("prefix:a"));
753    /// ```
754    pub fn into_initial(self) -> T {
755        T::from_scoped(self.full.into_initial(), self.ignored)
756    }
757
758    /// Unwrap the [`Snaplog`] into it's current snapshot.
759    ///
760    /// # Examples
761    /// ```
762    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
763    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
764    ///
765    /// snaplog.record("b");
766    /// snaplog.record("c");
767    /// assert_eq!(snaplog.into_current(), Prefixed::new("prefix:c"));
768    /// ```
769    pub fn into_current(self) -> T {
770        T::from_scoped(self.full.into_current(), self.ignored)
771    }
772
773    /// Unwrap the [`Snaplog`] into it's current snapshot.
774    ///
775    /// # Examples
776    /// ```
777    /// # use snaplog::{Select, scoped::{Snaplog, __Prefixed as Prefixed}};
778    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
779    ///
780    /// snaplog.record("b");
781    /// snaplog.record("c");
782    /// assert_eq!(snaplog.into_snapshot_at(Select::At(1)), Prefixed::new("prefix:b"));
783    /// ```
784    pub fn into_snapshot_at(self, select: Select) -> T {
785        T::from_scoped(self.full.into_snapshot_at(select), self.ignored)
786    }
787
788    /// Unwrap the [`Snaplog`] into it's history.
789    ///
790    /// # Examples
791    /// ```
792    /// # use snaplog::{full, scoped::{Snaplog, __Prefixed as Prefixed}};
793    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
794    ///
795    /// snaplog.record("b");
796    /// snaplog.record("c");
797    /// assert_eq!(
798    ///     snaplog.into_inner(),
799    ///     (full::Snaplog::from_history(["a", "b", "c"]), Some("prefix"))
800    /// );
801    /// ```
802    pub fn into_inner(self) -> (full::Snaplog<T::Scope>, T::Ignored) {
803        (self.full, self.ignored)
804    }
805}
806
807/// Thin implementations.
808impl<T: IntoScoped> Snaplog<T> {
809    /// Constructs a [`T::ThinScoped`][0] reference wrapper of the element at the given [`Select`].
810    ///
811    /// [0]: AsThinScoped::ThinScoped
812    ///
813    /// # Examples
814    /// ```
815    /// # use snaplog::{scoped::{Snaplog, __Prefixed as Prefixed}, Select};
816    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
817    ///
818    /// snaplog.record("b");
819    /// snaplog.record("c");
820    /// // note that the equality impl of T::ThinScoped and &T is given for this example
821    /// assert_eq!(snaplog.thin_snapshot_at(Select::At(1)), &Prefixed::new("prefix:b"));
822    /// ```
823    pub fn thin_snapshot_at(&self, select: Select) -> T::ThinScoped<'_>
824    where
825        T: AsThinScoped,
826    {
827        T::as_thin_scoped(self.snapshot_at(select), &self.ignored)
828    }
829
830    /// Constructs a [`T::ThinScopedMut`][0] reference wrapper of the element at the given
831    /// [`Select`].
832    ///
833    /// [0]: AsThinScopedMut::ThinScopedMut
834    ///
835    /// # Examples
836    /// ```
837    /// # use snaplog::{scoped::{Snaplog, __Prefixed as Prefixed}, Select};
838    /// let mut snaplog = Snaplog::new(Prefixed::new("prefix:a"));
839    ///
840    /// snaplog.record("b");
841    /// snaplog.record("c");
842    /// // note that the equality impl of T::ThinScopedMut and &T is given for this example
843    /// assert_eq!(snaplog.thin_snapshot_at_mut(Select::At(1)), &mut Prefixed::new("prefix:b"));
844    /// ```
845    pub fn thin_snapshot_at_mut(&mut self, select: Select) -> T::ThinScopedMut<'_>
846    where
847        T: AsThinScopedMut,
848    {
849        T::as_thin_scoped_mut(self.full.snapshot_at_mut(select), &mut self.ignored)
850    }
851}
852
853/// Unsafe implementations.
854impl<T: IntoScoped> Snaplog<T> {
855    /// Creates a new [`Snaplog`] for the given `history` backing vector.
856    ///
857    /// # Safety
858    /// The caller must ensure that the [`Vec`] contains at least one element.
859    ///
860    /// # Examples
861    /// ```
862    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
863    /// // this is fine
864    /// let snaplog: Snaplog<Prefixed> = unsafe {
865    ///     Snaplog::from_vec_unchecked(vec!["content"], None)
866    /// };
867    ///
868    /// // this will later fail
869    /// let snaplog: Snaplog<Prefixed> = unsafe {
870    ///     Snaplog::from_vec_unchecked(vec![], Some("prefix"))
871    /// };
872    /// ```
873    pub unsafe fn from_vec_unchecked(history: Vec<T::Scope>, ignored: T::Ignored) -> Self {
874        Self {
875            // SAFETY: invariants must be upheld by the caller
876            full: unsafe { full::Snaplog::from_vec_unchecked(history) },
877            ignored,
878        }
879    }
880
881    /// Creates a new [`Snaplog`] for the given `history` backing vector.
882    ///
883    /// # Safety
884    /// The caller must ensure that the `iter` contains at least one element.
885    ///
886    /// # Examples
887    /// ```
888    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
889    /// // this is fine
890    /// let snaplog: Snaplog<Prefixed> = unsafe {
891    ///     Snaplog::from_history_unchecked(["a", "b", "c"], None)
892    /// };
893    ///
894    /// // this will later fail
895    /// let snaplog: Snaplog<Prefixed> = unsafe {
896    ///     Snaplog::from_history_unchecked(std::iter::empty(), Some("prefix"))
897    /// };
898    /// ```
899    pub unsafe fn from_history_unchecked<I>(history: I, ignored: T::Ignored) -> Self
900    where
901        I: IntoIterator<Item = T::Scope>,
902    {
903        // SAFETY: invariants must be upheld by the caller
904        unsafe { Self::from_vec_unchecked(history.into_iter().collect(), ignored) }
905    }
906
907    /// Returns a mutable reference to the underlying [`Vec`]. The first element of this vector is
908    /// the initial element and is always set.
909    ///
910    /// # Safety
911    /// The caller must ensure that the [`Vec`] retains at least one element after mutation, this
912    /// element serves as the initial element.
913    ///
914    /// # Examples
915    /// ```
916    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
917    /// let mut snaplog: Snaplog<Prefixed> = Snaplog::try_from_history(
918    ///     ["a", "b", "c", "d", "e", "f", "g"],
919    ///     None,
920    /// )?;
921    ///
922    /// // SAFETY: no elements are removed
923    /// let inner = unsafe { snaplog.history_mut_vec() };
924    /// inner[5] = "h";
925    /// inner[6] = "i";
926    /// inner.drain(1..=3);
927    /// inner.push("j");
928    ///
929    /// assert_eq!(snaplog.history(), ["a", "e", "h", "i", "j"]);
930    /// # Ok::<_, Box<dyn std::error::Error>>(())
931    /// ```
932    pub unsafe fn history_mut_vec(&mut self) -> &mut Vec<T::Scope> {
933        // SAFETY: invariants must be upheld by the caller
934        unsafe { self.full.history_mut_vec() }
935    }
936
937    /// Returns a mutable reference to the ignored part.
938    ///
939    /// # Safety
940    /// There are no safety concerns in the current version but this is unsafe because mutation that
941    /// changes things like Hashing may not be expected in other parts of the code, the caller must
942    /// uphold invariants over the ignored part's mutation.
943    ///
944    /// # Examples
945    /// ```
946    /// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed};
947    /// let mut snaplog: Snaplog<Prefixed> = Snaplog::try_from_history(
948    ///     ["a", "b", "c", "d", "e"],
949    ///     None,
950    /// )?;
951    ///
952    /// // SAFETY: there are no invariants regarding Prefixed not having it's prefix mutated
953    /// let inner = unsafe { snaplog.ignored_mut() };
954    /// *inner = Some("new_prefix");
955    ///
956    /// assert_eq!(snaplog.into_current(), Prefixed::new("new_prefix:e"));
957    /// # Ok::<_, Box<dyn std::error::Error>>(())
958    /// ```
959    pub unsafe fn ignored_mut(&mut self) -> &mut T::Ignored {
960        &mut self.ignored
961    }
962}
963
964// first class traits
965impl<T: IntoScoped> Clone for Snaplog<T>
966where
967    T::Scope: Clone,
968    T::Ignored: Clone,
969{
970    fn clone(&self) -> Self {
971        Self {
972            full: self.full.clone(),
973            ignored: self.ignored.clone(),
974        }
975    }
976
977    fn clone_from(&mut self, source: &Self) {
978        self.full.clone_from(&source.full);
979        self.ignored.clone_from(&source.ignored);
980    }
981}
982
983impl<T: IntoScoped> std::ops::Index<Select> for Snaplog<T> {
984    type Output = T::Scope;
985
986    fn index(&self, index: Select) -> &Self::Output {
987        self.snapshot_at(index)
988    }
989}
990
991impl<T: IntoScoped> std::ops::IndexMut<Select> for Snaplog<T> {
992    fn index_mut(&mut self, index: Select) -> &mut Self::Output {
993        self.snapshot_at_mut(index)
994    }
995}
996
997// iter
998impl<T: IntoScoped> std::iter::Extend<T::Scope> for Snaplog<T> {
999    fn extend<I: IntoIterator<Item = T::Scope>>(&mut self, iter: I) {
1000        self.full.extend(iter);
1001    }
1002}
1003
1004// iter
1005/// An [`Iterator`] over all snapshot scopes and references to the ignored part.
1006///
1007/// # Examples
1008/// ```
1009/// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed, IntoScoped};
1010/// # type Scope = &'static str;
1011/// # type Ignored = Option<&'static str>;
1012/// let mut snaplog = Snaplog::new(Prefixed::new("prefix:content"));
1013/// let mut iter = snaplog.into_iter();
1014///
1015/// for snapshot in iter {
1016///     let s: (Scope, Ignored) = snapshot;
1017/// }
1018///
1019/// let mut snaplog = Snaplog::new(Prefixed::new("prefix:content"));
1020///
1021/// for snapshot in snaplog {
1022///     let s: (Scope, Ignored) = snapshot;
1023/// }
1024/// ```
1025#[derive(Debug)]
1026pub struct IntoIter<T: IntoScoped> {
1027    inner: full::IntoIter<T::Scope>,
1028    ignored: T::Ignored,
1029}
1030
1031impl<T: IntoScoped> IntoIter<T> {
1032    /// Returns a reference to the ignored part.
1033    pub fn ignored(&self) -> &T::Ignored {
1034        &self.ignored
1035    }
1036}
1037
1038impl<T: IntoScoped> Iterator for IntoIter<T>
1039where
1040    T::Ignored: Clone,
1041{
1042    type Item = (T::Scope, T::Ignored);
1043
1044    fn next(&mut self) -> Option<Self::Item> {
1045        // TODO: reduce last unnecessary clone by using a peeking iter and storing it as an Option
1046        self.inner.next().map(|s| (s, self.ignored.clone()))
1047    }
1048}
1049
1050impl<T: IntoScoped> IntoIterator for Snaplog<T>
1051where
1052    T::Ignored: Clone,
1053{
1054    type Item = (T::Scope, T::Ignored);
1055    type IntoIter = IntoIter<T>;
1056
1057    fn into_iter(self) -> Self::IntoIter {
1058        Self::IntoIter {
1059            inner: self.full.into_iter(),
1060            ignored: self.ignored,
1061        }
1062    }
1063}
1064
1065// TODO: exact size iter etc
1066
1067/// An [`Iterator`] over references to snapshot scopes and references to the ignored part.
1068///
1069/// # Examples
1070/// ```
1071/// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed, IntoScoped};
1072/// # type Scope = &'static str;
1073/// # type Ignored = Option<&'static str>;
1074/// let mut snaplog = Snaplog::new(Prefixed::new("prefix:content"));
1075///
1076/// for snapshot in snaplog.iter() {
1077///     let s: (&Scope, &Ignored) = snapshot;
1078/// }
1079///
1080/// for snapshot in &snaplog {
1081///     let s: (&Scope, &Ignored) = snapshot;
1082/// }
1083/// ```
1084#[derive(Debug)]
1085pub struct Iter<'cl, T: IntoScoped> {
1086    inner: full::Iter<'cl, T::Scope>,
1087    ignored: &'cl T::Ignored,
1088}
1089
1090impl<'cl, T: IntoScoped> Iter<'cl, T> {
1091    /// Returns a reference to the ignored part.
1092    pub fn ignored(&self) -> &'cl T::Ignored {
1093        self.ignored
1094    }
1095}
1096
1097impl<'cl, T: IntoScoped> Iterator for Iter<'cl, T> {
1098    type Item = (&'cl T::Scope, &'cl T::Ignored);
1099
1100    fn next(&mut self) -> Option<Self::Item> {
1101        self.inner.next().map(|s| (s, self.ignored))
1102    }
1103}
1104
1105impl<'cl, T: IntoScoped> IntoIterator for &'cl Snaplog<T> {
1106    type Item = (&'cl T::Scope, &'cl T::Ignored);
1107    type IntoIter = Iter<'cl, T>;
1108
1109    fn into_iter(self) -> Self::IntoIter {
1110        Iter {
1111            inner: self.full.iter(),
1112            ignored: &self.ignored,
1113        }
1114    }
1115}
1116
1117/// An [`Iterator`] over mutable references to snapshot scopes and references to the ignored part.
1118///
1119/// # Examples
1120/// ```
1121/// # use snaplog::scoped::{Snaplog, __Prefixed as Prefixed, IntoScoped};
1122/// # type Scope = &'static str;
1123/// # type Ignored = Option<&'static str>;
1124/// let mut snaplog = Snaplog::new(Prefixed::new("prefix:content"));
1125///
1126/// for snapshot in snaplog.iter_mut() {
1127///     let s: (&mut Scope, &Ignored) = snapshot;
1128/// }
1129///
1130/// for snapshot in &mut snaplog {
1131///     let s: (&mut Scope, &Ignored) = snapshot;
1132/// }
1133/// ```
1134#[derive(Debug)]
1135pub struct IterMut<'cl, T: IntoScoped> {
1136    inner: full::IterMut<'cl, T::Scope>,
1137    ignored: &'cl T::Ignored,
1138}
1139
1140impl<'cl, T: IntoScoped> IterMut<'cl, T> {
1141    /// Returns a reference to the ignored part.
1142    pub fn ignored(&self) -> &'cl T::Ignored {
1143        self.ignored
1144    }
1145}
1146
1147impl<'cl, T: IntoScoped> Iterator for IterMut<'cl, T> {
1148    type Item = (&'cl mut T::Scope, &'cl T::Ignored);
1149
1150    fn next(&mut self) -> Option<Self::Item> {
1151        self.inner.next().map(|s| (s, self.ignored))
1152    }
1153}
1154
1155impl<'cl, T: IntoScoped> IntoIterator for &'cl mut Snaplog<T> {
1156    type Item = (&'cl mut T::Scope, &'cl T::Ignored);
1157    type IntoIter = IterMut<'cl, T>;
1158
1159    fn into_iter(self) -> Self::IntoIter {
1160        IterMut {
1161            inner: self.full.iter_mut(),
1162            ignored: &mut self.ignored,
1163        }
1164    }
1165}
1166
1167// conversions
1168impl<T: IntoScoped> From<T> for Snaplog<T> {
1169    fn from(initial: T) -> Self {
1170        Self::new(initial)
1171    }
1172}
1173
1174impl<T: IntoScoped> From<Snaplog<T>> for (full::Snaplog<T::Scope>, T::Ignored) {
1175    fn from(snaplog: Snaplog<T>) -> Self {
1176        snaplog.into_inner()
1177    }
1178}
1179
1180impl<T: IntoScoped> TryFrom<(Vec<T::Scope>, T::Ignored)> for Snaplog<T> {
1181    type Error = EmptyHistoryError;
1182
1183    fn try_from(value: (Vec<T::Scope>, T::Ignored)) -> Result<Self, Self::Error> {
1184        Self::try_from_vec(value.0, value.1)
1185    }
1186}