ryo-storage 0.1.0

Persistent storage and transaction log for RYO
Documentation
//! Transaction log auto-save modes.
//!
//! Controls when session logs are automatically persisted to storage.

use serde::{Deserialize, Serialize};

/// Auto-save mode for transaction logs.
///
/// Determines when session logs are automatically saved to `~/.ryo/`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum TxLogMode {
    /// No automatic saving. Logs exist only in memory.
    /// Use this for testing or when you want full control over persistence.
    Off,

    /// Keep logs in memory only (current session).
    /// Logs are lost when the session ends unless explicitly saved.
    /// This is the default for backward compatibility.
    #[default]
    Memory,

    /// Save after each mutation is applied.
    /// Most granular tracking, highest I/O overhead.
    /// Useful for debugging or when mutations are infrequent.
    OnMutation,

    /// Save when `commit_changes()` is called on CodingWorld.
    /// Balanced approach: saves at logical completion points.
    /// Recommended for most use cases.
    OnCommit,
}

impl TxLogMode {
    /// Check if this mode requires automatic persistence.
    pub fn should_persist(&self) -> bool {
        matches!(self, TxLogMode::OnMutation | TxLogMode::OnCommit)
    }

    /// Check if this mode persists on each mutation.
    pub fn persist_on_mutation(&self) -> bool {
        matches!(self, TxLogMode::OnMutation)
    }

    /// Check if this mode persists on commit.
    pub fn persist_on_commit(&self) -> bool {
        matches!(self, TxLogMode::OnCommit)
    }

    /// Get a human-readable description.
    pub fn description(&self) -> &'static str {
        match self {
            TxLogMode::Off => "No logging",
            TxLogMode::Memory => "In-memory only",
            TxLogMode::OnMutation => "Save on each mutation",
            TxLogMode::OnCommit => "Save on commit",
        }
    }
}

impl std::fmt::Display for TxLogMode {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            TxLogMode::Off => write!(f, "off"),
            TxLogMode::Memory => write!(f, "memory"),
            TxLogMode::OnMutation => write!(f, "mutation"),
            TxLogMode::OnCommit => write!(f, "commit"),
        }
    }
}

impl std::str::FromStr for TxLogMode {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_lowercase().as_str() {
            "off" | "none" | "no" => Ok(TxLogMode::Off),
            "memory" | "mem" => Ok(TxLogMode::Memory),
            "mutation" | "onmutation" | "on-mutation" => Ok(TxLogMode::OnMutation),
            "commit" | "oncommit" | "on-commit" => Ok(TxLogMode::OnCommit),
            _ => Err(format!(
                "Unknown TxLogMode: '{}'. Valid options: off, memory, mutation, commit",
                s
            )),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_mode_properties() {
        assert!(!TxLogMode::Off.should_persist());
        assert!(!TxLogMode::Memory.should_persist());
        assert!(TxLogMode::OnMutation.should_persist());
        assert!(TxLogMode::OnCommit.should_persist());

        assert!(TxLogMode::OnMutation.persist_on_mutation());
        assert!(!TxLogMode::OnCommit.persist_on_mutation());

        assert!(!TxLogMode::OnMutation.persist_on_commit());
        assert!(TxLogMode::OnCommit.persist_on_commit());
    }

    #[test]
    fn test_mode_parsing() {
        assert_eq!("off".parse::<TxLogMode>().unwrap(), TxLogMode::Off);
        assert_eq!("memory".parse::<TxLogMode>().unwrap(), TxLogMode::Memory);
        assert_eq!(
            "mutation".parse::<TxLogMode>().unwrap(),
            TxLogMode::OnMutation
        );
        assert_eq!("commit".parse::<TxLogMode>().unwrap(), TxLogMode::OnCommit);

        // Aliases
        assert_eq!("none".parse::<TxLogMode>().unwrap(), TxLogMode::Off);
        assert_eq!(
            "on-commit".parse::<TxLogMode>().unwrap(),
            TxLogMode::OnCommit
        );
    }

    #[test]
    fn test_mode_display() {
        assert_eq!(TxLogMode::Off.to_string(), "off");
        assert_eq!(TxLogMode::Memory.to_string(), "memory");
        assert_eq!(TxLogMode::OnMutation.to_string(), "mutation");
        assert_eq!(TxLogMode::OnCommit.to_string(), "commit");
    }
}