Skip to main content

ryo_storage/storage/
mode.rs

1//! Transaction log auto-save modes.
2//!
3//! Controls when session logs are automatically persisted to storage.
4
5use serde::{Deserialize, Serialize};
6
7/// Auto-save mode for transaction logs.
8///
9/// Determines when session logs are automatically saved to `~/.ryo/`.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
11pub enum TxLogMode {
12    /// No automatic saving. Logs exist only in memory.
13    /// Use this for testing or when you want full control over persistence.
14    Off,
15
16    /// Keep logs in memory only (current session).
17    /// Logs are lost when the session ends unless explicitly saved.
18    /// This is the default for backward compatibility.
19    #[default]
20    Memory,
21
22    /// Save after each mutation is applied.
23    /// Most granular tracking, highest I/O overhead.
24    /// Useful for debugging or when mutations are infrequent.
25    OnMutation,
26
27    /// Save when `commit_changes()` is called on CodingWorld.
28    /// Balanced approach: saves at logical completion points.
29    /// Recommended for most use cases.
30    OnCommit,
31}
32
33impl TxLogMode {
34    /// Check if this mode requires automatic persistence.
35    pub fn should_persist(&self) -> bool {
36        matches!(self, TxLogMode::OnMutation | TxLogMode::OnCommit)
37    }
38
39    /// Check if this mode persists on each mutation.
40    pub fn persist_on_mutation(&self) -> bool {
41        matches!(self, TxLogMode::OnMutation)
42    }
43
44    /// Check if this mode persists on commit.
45    pub fn persist_on_commit(&self) -> bool {
46        matches!(self, TxLogMode::OnCommit)
47    }
48
49    /// Get a human-readable description.
50    pub fn description(&self) -> &'static str {
51        match self {
52            TxLogMode::Off => "No logging",
53            TxLogMode::Memory => "In-memory only",
54            TxLogMode::OnMutation => "Save on each mutation",
55            TxLogMode::OnCommit => "Save on commit",
56        }
57    }
58}
59
60impl std::fmt::Display for TxLogMode {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        match self {
63            TxLogMode::Off => write!(f, "off"),
64            TxLogMode::Memory => write!(f, "memory"),
65            TxLogMode::OnMutation => write!(f, "mutation"),
66            TxLogMode::OnCommit => write!(f, "commit"),
67        }
68    }
69}
70
71impl std::str::FromStr for TxLogMode {
72    type Err = String;
73
74    fn from_str(s: &str) -> Result<Self, Self::Err> {
75        match s.to_lowercase().as_str() {
76            "off" | "none" | "no" => Ok(TxLogMode::Off),
77            "memory" | "mem" => Ok(TxLogMode::Memory),
78            "mutation" | "onmutation" | "on-mutation" => Ok(TxLogMode::OnMutation),
79            "commit" | "oncommit" | "on-commit" => Ok(TxLogMode::OnCommit),
80            _ => Err(format!(
81                "Unknown TxLogMode: '{}'. Valid options: off, memory, mutation, commit",
82                s
83            )),
84        }
85    }
86}
87
88#[cfg(test)]
89mod tests {
90    use super::*;
91
92    #[test]
93    fn test_mode_properties() {
94        assert!(!TxLogMode::Off.should_persist());
95        assert!(!TxLogMode::Memory.should_persist());
96        assert!(TxLogMode::OnMutation.should_persist());
97        assert!(TxLogMode::OnCommit.should_persist());
98
99        assert!(TxLogMode::OnMutation.persist_on_mutation());
100        assert!(!TxLogMode::OnCommit.persist_on_mutation());
101
102        assert!(!TxLogMode::OnMutation.persist_on_commit());
103        assert!(TxLogMode::OnCommit.persist_on_commit());
104    }
105
106    #[test]
107    fn test_mode_parsing() {
108        assert_eq!("off".parse::<TxLogMode>().unwrap(), TxLogMode::Off);
109        assert_eq!("memory".parse::<TxLogMode>().unwrap(), TxLogMode::Memory);
110        assert_eq!(
111            "mutation".parse::<TxLogMode>().unwrap(),
112            TxLogMode::OnMutation
113        );
114        assert_eq!("commit".parse::<TxLogMode>().unwrap(), TxLogMode::OnCommit);
115
116        // Aliases
117        assert_eq!("none".parse::<TxLogMode>().unwrap(), TxLogMode::Off);
118        assert_eq!(
119            "on-commit".parse::<TxLogMode>().unwrap(),
120            TxLogMode::OnCommit
121        );
122    }
123
124    #[test]
125    fn test_mode_display() {
126        assert_eq!(TxLogMode::Off.to_string(), "off");
127        assert_eq!(TxLogMode::Memory.to_string(), "memory");
128        assert_eq!(TxLogMode::OnMutation.to_string(), "mutation");
129        assert_eq!(TxLogMode::OnCommit.to_string(), "commit");
130    }
131}