aterm 0.20.0

Implementation of the Annotated Terms data structure
Documentation
#![allow(unknown_lints)]

use interface::{ATerm as ATermT, ATermFactory as ATermFactoryT,
                SharedATermFactory as SharedATermFactoryT};
use utils::insert_or_get;
use rc::{ATerm, Term, TermPlaceholder};
use bad_idea::BrokenF32;

use std::collections::HashSet;
use std::hash::Hash;
use std::marker::PhantomData;
use std::hash::BuildHasher;
use std::borrow::Cow;
use std::cell::RefCell;
use std::rc::Rc;

use string_share::StringShare;

pub struct ATermFactory<'s, B: Hash + Eq, H: BuildHasher> {
    string_cache: RefCell<StringShare<H>>,
    arena: RefCell<HashSet<Rc<ATerm<'s, B>>, H>>,
    _nothing: PhantomData<B>,
}

impl<'s, B: Hash + Eq, H: BuildHasher + Default> ATermFactory<'s, B, H> {
    pub fn new() -> Self {
        ATermFactory {
            string_cache: RefCell::new(StringShare::new()),
            arena: RefCell::new(HashSet::default()),
            _nothing: PhantomData,
        }
    }

    pub fn with_capacity(capacity: usize) -> Self {
        ATermFactory {
            string_cache: RefCell::new(StringShare::new()),
            arena: RefCell::new(HashSet::with_capacity_and_hasher(
                capacity,
                Default::default(),
            )),
            _nothing: PhantomData,
        }
    }
}

impl<'s, B: Hash + Eq, H: BuildHasher + Default> Default for ATermFactory<'s, B, H> {
    fn default() -> Self {
        Self::new()
    }
}

impl<'s, B: 's + Clone + Hash + Eq, H: 's + BuildHasher + Default> ATermFactoryT<'s>
    for ATermFactory<'s, B, H> {
    type ATerm = ATerm<'s, B>;
    type ATermRef = Rc<ATerm<'s, B>>;

    fn with_annos<A>(&'s self, term: Self::ATermRef, annos: A) -> Self::ATermRef
    where
        A: IntoIterator<Item = Self::ATermRef>,
    {
        insert_or_get(
            &mut self.arena.borrow_mut(),
            Rc::new(ATerm::with_annos(term.term.clone(), annos)),
        ).clone()
    }

    fn application<I, S>(&'s self, constructor: S, children: I) -> Self::ATermRef
    where
        I: IntoIterator<Item = Self::ATermRef>,
        S: Into<Cow<'s, str>>,
    {
        use rc::Term::Application;
        use utils::extend_lifetime_mut;

        // I'm not sure why I even need to extend the lifetime here, so this could be totally wrong!
        // But if we add something to the string cache, and then use a reference to it, that
        // *should* be fine right?
        let mut string_cache = unsafe { extend_lifetime_mut(&mut self.string_cache.borrow_mut()) };
        let cons = string_cache.insert(constructor.into().as_ref());
        Rc::new(ATerm::no_annos(Application(
            cons,
            children.into_iter().collect::<Vec<_>>().into_boxed_slice(),
        )))
    }

    fn int(&'s self, value: i32) -> Self::ATermRef {
        Rc::new(ATerm::no_annos(Term::Int(value)))
    }

    fn string<S>(&'s self, value: S) -> Self::ATermRef
    where
        S: Into<Cow<'s, str>>,
    {
        self.application(::utils::string_escape(&value.into()), ::std::iter::empty())
    }

    fn tuple<I>(&'s self, children: I) -> Self::ATermRef
    where
        I: IntoIterator<Item = Self::ATermRef>,
    {
        self.application(String::new(), children)
    }

    fn real(&'s self, value: f32) -> Self::ATermRef {
        Rc::new(ATerm::no_annos(Term::Real(BrokenF32(value))))
    }

    fn list<I>(&'s self, value: I) -> Self::ATermRef
    where
        I: IntoIterator<Item = Self::ATermRef>,
    {
        Rc::new(ATerm::no_annos(Term::List(
            value.into_iter().collect::<Vec<_>>().into_boxed_slice(),
        )))
    }

    fn placeholder(&'s self, value: TermPlaceholder<Self::ATermRef>) -> Self::ATermRef {
        Rc::new(ATerm::no_annos(Term::Placeholder(value)))
    }

    fn blob(&'s self, value: <Self::ATerm as ATermT<'s>>::Blob) -> Self::ATermRef {
        Rc::new(ATerm::no_annos(Term::Blob(value)))
    }

    fn long(&'s self, value: i64) -> Self::ATermRef {
        Rc::new(ATerm::no_annos(Term::Long(value)))
    }
}

impl<'s, B, H> SharedATermFactoryT<'s> for ATermFactory<'s, B, H>
where
    B: 's + Clone + Hash + Eq,
    H: 's + BuildHasher + Default,
{
    fn get_shared(&'s self, value: Self::ATermRef) -> Self::ATermRef
    where
        Self::ATermRef: Clone,
    {
        insert_or_get(&mut self.arena.borrow_mut(), value.clone()).clone()
    }
}