use std::sync::{Arc, RwLock};
use crate::sync::MithridatistLockResult as _;
#[derive(Debug)]
pub enum HotswapState<T: Send + Sync + 'static> {
Parent(Arc<RwLock<Arc<T>>>),
Child(Arc<T>),
}
impl<T: Send + Sync + 'static> HotswapState<T> {
pub fn new(state: T) -> Self {
Self::from(Arc::new(state))
}
pub fn is_parent(&self) -> bool {
matches!(self, Self::Parent(_))
}
pub fn replace_parent_state(&self, new_state: T) -> Option<Arc<T>> {
match self {
Self::Parent(inner_lock) => Some(std::mem::replace(
&mut inner_lock.write().mithridate(),
Arc::new(new_state),
)),
Self::Child(_) => None,
}
}
pub fn clone_as_parent(&self) -> Self {
match self {
Self::Parent(inner_lock) => Self::Parent(inner_lock.clone()),
Self::Child(inner) => Self::Parent(Arc::new(RwLock::new(inner.clone()))),
}
}
pub fn clone_as_child(&self) -> Self {
match self {
Self::Parent(inner_lock) => Self::Child(inner_lock.read().mithridate().clone()),
Self::Child(inner) => Self::Child(inner.clone()),
}
}
pub fn into_inner(self) -> Arc<T> {
match self {
HotswapState::Parent(inner_lock) => inner_lock.read().mithridate().clone(),
HotswapState::Child(inner) => inner,
}
}
pub fn as_inner_ref(&self) -> &T {
match self {
HotswapState::Parent(_) => panic!("HotswapState::is_inner_ref was called on a parent."),
HotswapState::Child(inner) => inner.as_ref(),
}
}
pub fn try_as_inner_ref(&self) -> Option<&T> {
match self {
HotswapState::Parent(_) => None,
HotswapState::Child(inner) => Some(inner.as_ref()),
}
}
}
impl<T: Send + Sync + 'static> Clone for HotswapState<T> {
fn clone(&self) -> Self {
match self {
Self::Parent(inner_lock) => Self::Parent(inner_lock.clone()),
Self::Child(inner) => Self::Child(inner.clone()),
}
}
}
impl<T: Send + Sync + 'static> From<Arc<T>> for HotswapState<T> {
fn from(value: Arc<T>) -> Self {
Self::Parent(Arc::new(RwLock::new(value)))
}
}
impl<T: Send + Sync + 'static> From<HotswapState<T>> for Arc<T> {
fn from(value: HotswapState<T>) -> Self {
value.into_inner()
}
}
impl<T: Send + Sync + 'static> From<&HotswapState<T>> for Arc<T> {
fn from(value: &HotswapState<T>) -> Self {
value.clone_as_child().into_inner()
}
}
#[cfg(feature = "http")]
impl<T: Send + Sync + 'static> axum::extract::FromRef<HotswapState<T>> for Arc<T> {
fn from_ref(input: &HotswapState<T>) -> Self {
input.clone_as_child().into_inner()
}
}
#[cfg(test)]
#[path = "../tests/types/hotswap_state.rs"]
mod tests;