use std::sync::Arc;
use crate::utils::linked_list::{LinkedList, SharedNode};
#[derive(Clone, Debug)]
pub struct Snapshot {
inner: SharedNode<InnerSnapshot>,
}
impl Snapshot {
pub(crate) fn new(inner: SharedNode<InnerSnapshot>) -> Self {
Self { inner }
}
pub(crate) fn inner(&self) -> SharedNode<InnerSnapshot> {
Arc::clone(&self.inner)
}
pub(crate) fn sequence_number(&self) -> u64 {
self.inner.read().element.sequence_number()
}
}
#[derive(Debug)]
pub(crate) struct InnerSnapshot {
sequence_number: u64,
}
impl InnerSnapshot {
pub(crate) fn new(sequence_number: u64) -> Self {
Self { sequence_number }
}
pub(crate) fn sequence_number(&self) -> u64 {
self.sequence_number
}
}
pub(crate) struct SnapshotList {
list: LinkedList<InnerSnapshot>,
}
impl SnapshotList {
pub(crate) fn new() -> Self {
Self {
list: LinkedList::new(),
}
}
pub(crate) fn new_snapshot(&mut self, sequence_number: u64) -> Snapshot {
assert!(
self.is_empty() || self.newest().read().element.sequence_number() <= sequence_number
);
let snapshot = InnerSnapshot::new(sequence_number);
Snapshot::new(self.list.push(snapshot))
}
pub(crate) fn delete_snapshot(&mut self, snapshot: Snapshot) {
self.list.remove_node(snapshot.inner());
}
pub(crate) fn is_empty(&self) -> bool {
self.list.is_empty()
}
pub(crate) fn oldest(&self) -> SharedNode<InnerSnapshot> {
self.list.head().unwrap()
}
pub(crate) fn newest(&self) -> SharedNode<InnerSnapshot> {
self.list.tail().unwrap()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_new_snapshot_can_be_requested() {
let mut snapshots = SnapshotList::new();
let snapshot1 = snapshots.new_snapshot(1000);
assert!(Arc::ptr_eq(&snapshot1.inner(), &snapshots.newest()));
let snapshot2 = snapshots.new_snapshot(2000);
assert!(Arc::ptr_eq(&snapshot2.inner(), &snapshots.newest()));
assert!(Arc::ptr_eq(&snapshot1.inner(), &snapshots.oldest()));
}
#[test]
fn snapshots_can_be_removed() {
let mut snapshots = SnapshotList::new();
let snapshot1 = snapshots.new_snapshot(1000);
let snapshot2 = snapshots.new_snapshot(2000);
snapshots.delete_snapshot(snapshot1);
assert!(Arc::ptr_eq(&snapshot2.inner(), &snapshots.oldest()));
snapshots.delete_snapshot(snapshot2);
assert!(snapshots.is_empty());
}
}