aterm 0.20.0

Implementation of the Annotated Terms data structure
Documentation
use std::collections::HashMap;
use std::hash::{BuildHasher, Hash, Hasher};
use std::borrow::{Borrow, Cow};
use std::ops::Deref;
use std::fmt;

use typed_arena::Arena;

use print::ATermWrite;

pub struct StringShare<H: BuildHasher> {
    map: HashMap<&'static str, &'static str, H>,
    // Hmm, maybe a Vec is enough here, since String is already heap-allocated so we can take &str
    // from it anyway. That is, when you push extra strings on and the Vec reallocates the content
    // to a larger array, the Strings should stay in the same place.
    arena: Arena<String>,
}

impl<H: BuildHasher + Default> StringShare<H> {
    pub fn new() -> Self {
        StringShare {
            map: HashMap::default(),
            arena: Arena::new(),
        }
    }

    pub fn with_capacity(cap: usize) -> Self {
        StringShare {
            map: HashMap::with_capacity_and_hasher(cap, Default::default()),
            arena: Arena::with_capacity(cap),
        }
    }
}

impl<H: BuildHasher + Default> Default for StringShare<H> {
    fn default() -> Self {
        Self::new()
    }
}

impl<H: BuildHasher> StringShare<H> {
    pub fn insert<'s, Q>(&mut self, item: Q) -> InternedString
    where
        Q: Into<Cow<'s, str>>,
    {
        use utils::extend_lifetime;

        let itemcow = item.into();
        InternedString(self.map.get::<str>(itemcow.borrow()).map(|&s| s).unwrap_or_else(|| {
            // Extending the lifetime of the allocated string here, so we can put it into the map
            // without issues and return a reference to it. The lifetime of the return value is
            // constrained to the lifetime of self, so that should be fine.
            let itemref: &'static str = unsafe {
                extend_lifetime(self.arena.alloc(itemcow.into_owned()))
            };
            self.map.insert(itemref, itemref);
            itemref
        }))
    }
}

#[derive(Eq, Clone, Copy)]
pub struct InternedString<'s>(&'s str);

impl<'s> PartialEq<InternedString<'s>> for InternedString<'s> {
    fn eq(&self, other: &InternedString<'s>) -> bool {
        use std::ptr;
        ptr::eq(self.0, other.0)
    }
}

impl<'s> Hash for InternedString<'s> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        (((self.0 as *const str) as *const u8) as usize).hash(state)
    }
}

impl<'s> PartialEq<str> for InternedString<'s> {
    fn eq(&self, other: &str) -> bool {
        self.0 == other
    }
}

impl<'a, 's> PartialEq<&'a str> for InternedString<'s> {
    fn eq(&self, other: &&'a str) -> bool {
        self.0 == *other
    }
}

impl<'s> Deref for InternedString<'s> {
    type Target = str;

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

impl<'s> Borrow<&'s str> for InternedString<'s> {
    fn borrow(&self) -> &&'s str {
        &self.0
    }
}

impl<'s> Borrow<str> for InternedString<'s> {
    fn borrow(&self) -> &str {
        self.0
    }
}

impl<'s> From<InternedString<'s>> for Cow<'s, str> {
    fn from(s: InternedString<'s>) -> Self {
        s.0.into()
    }
}

impl<'s> From<InternedString<'s>> for ::std::path::PathBuf {
    fn from(s: InternedString<'s>) -> Self {
        s.0.into()
    }
}

impl<'s> From<InternedString<'s>> for String {
    fn from(s: InternedString<'s>) -> Self {
        s.0.into()
    }
}

impl<'s> From<InternedString<'s>> for &'s str {
    fn from(s: InternedString<'s>) -> Self {
        s.0
    }
}

impl<'s> AsRef<str> for InternedString<'s> {
    fn as_ref(&self) -> &str {
        self.0
    }
}

impl<'s> AsRef<::std::ffi::OsStr> for InternedString<'s> {
    fn as_ref(&self) -> &::std::ffi::OsStr {
        self.0.as_ref()
    }
}

impl<'s> ATermWrite for InternedString<'s> {
    fn to_ascii<W: fmt::Write>(&self, writer: &mut W) -> fmt::Result {
        write!(writer, "{}", ::utils::string_escape(self.0))
    }
}

impl<'s> fmt::Debug for InternedString<'s> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl<'s> fmt::Display for InternedString<'s> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}