🏡 index : ~doyle/packfile.git

use std::hash::Hasher;
use std::{
    borrow::Cow,
    fmt::{Display, Formatter},
    hash::Hash,
    ops::Deref,
    sync::Arc,
};

#[derive(Debug, Eq)]
pub enum ArcOrCowStr {
    Arc(Arc<str>),
    Cow(Cow<'static, str>),
}

impl Hash for ArcOrCowStr {
    fn hash<H: Hasher>(&self, state: &mut H) {
        (**self).hash(state);
    }
}

impl PartialEq<ArcOrCowStr> for ArcOrCowStr {
    fn eq(&self, other: &ArcOrCowStr) -> bool {
        **self == **other
    }
}

impl From<Arc<str>> for ArcOrCowStr {
    fn from(v: Arc<str>) -> Self {
        Self::Arc(v)
    }
}

impl From<Cow<'static, str>> for ArcOrCowStr {
    fn from(v: Cow<'static, str>) -> Self {
        Self::Cow(v)
    }
}

impl From<&'static str> for ArcOrCowStr {
    fn from(v: &'static str) -> Self {
        Self::Cow(Cow::Borrowed(v))
    }
}

impl From<String> for ArcOrCowStr {
    fn from(v: String) -> Self {
        Self::Cow(Cow::Owned(v))
    }
}

impl AsRef<str> for ArcOrCowStr {
    fn as_ref(&self) -> &str {
        match self {
            Self::Arc(v) => v.as_ref(),
            Self::Cow(v) => v.as_ref(),
        }
    }
}

impl Deref for ArcOrCowStr {
    type Target = str;

    fn deref(&self) -> &Self::Target {
        self.as_ref()
    }
}

impl Display for ArcOrCowStr {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        std::fmt::Display::fmt(&**self, f)
    }
}

#[cfg(test)]
mod test {
    mod arc_or_cow_str {
        use crate::util::ArcOrCowStr;
        use std::borrow::Cow;
        use std::sync::Arc;

        #[test]
        fn from_arc() {
            assert_eq!(
                ArcOrCowStr::from(Arc::from("hello world".to_string())),
                "hello world".into()
            );
        }

        #[test]
        fn from_cow() {
            assert_eq!(
                ArcOrCowStr::from(Cow::Borrowed("hello world")),
                "hello world".into()
            );
        }

        #[test]
        fn from_string() {
            assert_eq!(
                ArcOrCowStr::from("hello world".to_string()),
                "hello world".into()
            );
        }
    }
}