use std::{fmt::Debug, hash::Hash, marker::PhantomData, ops::Deref};
use super::invariant::NonEmptyCleanSegmentStr;
pub trait TSegmentSafeToken:
'static + Debug + Clone + PartialEq + Eq + Hash + Send + Sync + Unpin
{
fn token() -> &'static NonEmptyCleanSegmentStr;
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ConflictFreeToken<T: TSegmentSafeToken>(NonEmptyCleanSegmentStr, PhantomData<T>);
#[derive(Debug, Clone, thiserror::Error)]
#[error("Given token is not conflict free.")]
pub struct TokenIsNotConflictFree;
impl<T: TSegmentSafeToken> TryFrom<NonEmptyCleanSegmentStr> for ConflictFreeToken<T> {
type Error = TokenIsNotConflictFree;
#[inline]
fn try_from(value: NonEmptyCleanSegmentStr) -> Result<Self, Self::Error> {
if value.contains(T::token().as_ref().as_ref()) {
return Err(TokenIsNotConflictFree);
}
Ok(Self(value, PhantomData))
}
}
impl<D: TSegmentSafeToken> TryFrom<&str> for ConflictFreeToken<D> {
type Error = TokenIsNotConflictFree;
#[inline]
fn try_from(token_str: &str) -> Result<Self, Self::Error> {
let clean_token =
NonEmptyCleanSegmentStr::try_new_from(token_str).map_err(|_| TokenIsNotConflictFree)?;
clean_token.try_into()
}
}
impl<D: TSegmentSafeToken> Deref for ConflictFreeToken<D> {
type Target = NonEmptyCleanSegmentStr;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}