transactional 0.3.1

A simple optimistic lock-free confirmation-based transactional model for Rust.
Documentation
use std::thread::{self, ThreadId};

use crate::{prelude::*, thread::ThreadSafetyChecker};
pub trait StateFactory {
    type Item: ToString;

    fn new(value: Self::Item) -> State<Self::Item>;
}

pub trait StateBehavior {
    type Item: ToString;

    fn get(&self) -> Option<&Self::Item>;
    fn get_previous(&self) -> Option<&Self::Item>;

    fn transact(
        &mut self,
        value: Option<Self::Item>,
    ) -> Transaction<'_, Self::Item, Transacting>;
}

pub(crate) trait StateChangeBehavior {
    type Item: ToString;
    type F: Fn(Option<&Self::Item>, Option<&Self::Item>) -> Result<(), Error>;

    fn modify(&mut self, value: Option<Self::Item>);
    fn rollback(&mut self);
    fn commit(&mut self);
}

#[derive(Debug)]
/// Represents a state container for a value that tracks its current, previous, and before-previous states.
///
/// This generic struct allows tracking changes to a value over time, with the ability to store
/// the current value, its previous value, and the value before the previous one. The type `T`
/// must implement the `ToString` trait.
///
/// # Type Parameters
///
/// * `T` - The type of the value being tracked, defaulting to `i32` if not specified.
///
/// # Fields
///
/// * `before_previous` - The value that existed before the previous value.
/// * `previous` - The previous value of the state.
/// * `current` - The current value of the state.
/// * `transacting` - A flag indicating whether a transaction is in progress (to be removed).
///
/// /// # Thread Safety
///
/// This type is intentionally not thread-safe and will panic if accessed from multiple threads.
/// For multi-threaded applications, use thread-local storage to maintain separate instances
/// per thread.
///
/// ```rust
/// use std::thread;
/// use std::cell::RefCell;
/// use transactional::prelude::*;
///
/// thread_local! {
///     static LOCAL_STATE: RefCell<State<i32>> = RefCell::new(State::new(0));
/// }
///
/// // Safe usage: each thread accesses its own instance
/// thread::spawn(|| {
///     LOCAL_STATE.with(|state| {
///         let mut state = state.borrow_mut();
///         // Use state safely within this thread
///     });
/// });
/// ```
pub struct State<T = i32>
where
    T: ToString,
{
    before_previous: Option<T>,
    previous: Option<T>,
    current: Option<T>,
    provisional: bool,
    thread_id: ThreadId,
}
impl<T> Default for State<T>
where
    T: ToString,
{
    fn default() -> Self {
        Self {
            before_previous: None,
            previous: None,
            current: None,
            provisional: false,
            thread_id: thread::current().id(),
        }
    }
}

impl<T> StateFactory for State<T>
where
    T: ToString,
{
    type Item = T;

    fn new(value: Self::Item) -> State<Self::Item> {
        Self {
            before_previous: None,
            previous: None,
            current: Some(value),
            provisional: false,
            thread_id: thread::current().id(),
        }
    }
}

impl<T> StateBehavior for State<T>
where
    T: ToString,
{
    type Item = T;

    fn get(&self) -> Option<&T> {
        self.ensure_thread_safety();
        self.current.as_ref()
    }

    fn get_previous(&self) -> Option<&T> {
        self.ensure_thread_safety();
        self.previous.as_ref()
    }

    fn transact(
        &mut self,
        value: Option<Self::Item>,
    ) -> Transaction<'_, Self::Item, Transacting> {
        self.ensure_thread_safety();
        Transaction::new(self, value)
    }
}

impl<T> StateChangeBehavior for State<T>
where
    T: ToString,
{
    type Item = T;
    type F = fn(Option<&T>, Option<&T>) -> Result<(), Error>;

    fn modify(&mut self, value: Option<Self::Item>) {
        self.ensure_thread_safety();
        self.before_previous = self.previous.take();
        self.previous = self.current.take();
        self.current = value;
        self.provisional = true;
    }

    fn rollback(&mut self) {
        self.ensure_thread_safety();
        self.current = self.previous.take();
        self.previous = self.before_previous.take();
        self.before_previous = None;
        self.provisional = false;
    }

    fn commit(&mut self) {
        self.ensure_thread_safety();
        self.provisional = false;
    }
}

impl<T> ThreadSafetyChecker for State<T>
where
    T: ToString,
{
    fn get_owner_thread_id(&self) -> std::thread::ThreadId {
        self.thread_id
    }
}