use std::path::PathBuf;
use std::sync::atomic::AtomicUsize;
use std::sync::{Arc, Mutex};
use crate::checkpoint::ShadowRepo;
use crate::checkpoint_log::CheckpointLogWriter;
use crate::tools::TouchedFiles;
pub(crate) struct CheckpointState {
pub(crate) shadow: Option<Arc<ShadowRepo>>,
pub(crate) session_id: Option<String>,
pub(crate) turn_index: Arc<AtomicUsize>,
pub(crate) writer: Option<Arc<Mutex<CheckpointLogWriter>>>,
pub(crate) touched_files: Option<Arc<Mutex<TouchedFiles>>>,
pub(crate) log_path: Option<PathBuf>,
}
impl CheckpointState {
pub(crate) fn disabled() -> Self {
Self {
shadow: None,
session_id: None,
turn_index: Arc::new(AtomicUsize::new(0)),
writer: None,
touched_files: None,
log_path: None,
}
}
pub(crate) fn enabled(&self) -> bool {
self.shadow.is_some() && self.session_id.is_some()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::atomic::Ordering;
#[test]
fn turn_index_starts_at_zero_and_increments() {
let state = CheckpointState::disabled();
assert_eq!(state.turn_index.load(Ordering::Relaxed), 0);
state.turn_index.fetch_add(1, Ordering::Relaxed);
state.turn_index.fetch_add(1, Ordering::Relaxed);
assert_eq!(state.turn_index.load(Ordering::Relaxed), 2);
}
#[test]
fn disabled_state_has_no_checkpoint_subsystem() {
let state = CheckpointState::disabled();
assert!(!state.enabled());
assert!(state.shadow.is_none());
assert!(state.session_id.is_none());
assert!(state.writer.is_none());
assert!(state.touched_files.is_none());
assert!(state.log_path.is_none());
}
#[test]
fn touched_files_lifecycle() {
let state = CheckpointState::disabled();
assert!(state.touched_files.is_none());
let touched = Arc::new(Mutex::new(TouchedFiles::new()));
let mut with_touched = CheckpointState::disabled();
with_touched.touched_files = Some(touched.clone());
{
let mut guard = touched.lock().unwrap();
guard.paths.insert("src/foo.rs".into());
guard.paths.insert("Cargo.toml".into());
}
{
let guard = touched.lock().unwrap();
assert_eq!(guard.paths_sorted(), vec!["Cargo.toml", "src/foo.rs"]);
}
{
let mut guard = touched.lock().unwrap();
guard.paths.clear();
}
assert!(touched.lock().unwrap().is_empty());
}
}