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)]
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
}
}