aterm 0.20.0

Implementation of the Annotated Terms data structure
Documentation
use std::borrow::Borrow;
use std::borrow::Cow;

use string_share::InternedString;

pub use bad_idea::BrokenF32;

/// An all-in-one package for building `ATerm`s. Maybe be pure, or have internal mutability to give
/// you maximally shared `ATerm`s.
pub trait ATermFactory<'s> {
    /// The `ATerm` the factory builds
    type ATerm: ATerm<'s, Rec = Self::ATermRef>;
    /// The reference to an `ATerm` that's returned. You usually want these to be cheaply cloneable!
    type ATermRef: Borrow<Self::ATerm>;

    fn int(&'s self, value: i32) -> Self::ATermRef;
    /// The string variant in ATerms is represented as an application with zero children!
    fn string<S>(&'s self, value: S) -> Self::ATermRef
    where
        S: Into<Cow<'s, str>>;
    /// The tuple in ATerms is represented as an application with an empty constructor string!
    fn tuple<I>(&'s self, children: I) -> Self::ATermRef
    where
        I: IntoIterator<Item = Self::ATermRef>;
    fn real(&'s self, value: f32) -> Self::ATermRef;
    fn application<I, S>(&'s self, constructor: S, children: I) -> Self::ATermRef
    where
        I: IntoIterator<Item = Self::ATermRef>,
        S: Into<Cow<'s, str>>;
    fn list<I>(&'s self, value: I) -> Self::ATermRef
    where
        I: IntoIterator<Item = Self::ATermRef>;
    fn placeholder(&'s self, value: TermPlaceholder<Self::ATermRef>) -> Self::ATermRef;
    fn blob(&'s self, value: <Self::ATerm as ATerm<'s>>::Blob) -> Self::ATermRef;
    fn long(&'s self, value: i64) -> Self::ATermRef;

    fn with_annos<A>(&'s self, term: Self::ATermRef, annos: A) -> Self::ATermRef
    where
        A: IntoIterator<Item = Self::ATermRef>;
}

pub trait SharedATermFactory<'s>: ATermFactory<'s> {
    fn get_shared(&'s self, value: Self::ATermRef) -> Self::ATermRef;
}

pub trait ATerm<'s> {
    /// Basically the current type, but you may want to add something extra, so this is more
    /// flexible.
    type Rec: Borrow<Self>;
    /// The extension point to add more variants to terms.
    type Blob;

    #[inline]
    fn get_annotations(&self) -> &[Self::Rec];

    #[inline]
    fn get_int(&self) -> Option<i32>;

    #[inline]
    fn get_long(&self) -> Option<i64>;

    #[inline]
    fn get_real(&self) -> Option<f32>;

    #[inline]
    fn get_application(&self) -> Option<(InternedString<'s>, &[Self::Rec])>;

    #[inline]
    fn get_list(&self) -> Option<Vec<Self::Rec>>;

    #[inline]
    fn get_placeholder(&self) -> Option<&TermPlaceholder<Self::Rec>>;

    #[inline]
    fn get_blob(&self) -> Option<&Self::Blob>;
}

/// These placeholders match the constructors of Term.
/// The Application has sub-placeholders for the children of the constructor. The Term placeholder
/// is basically a wildcard, it matches anything.
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum TermPlaceholder<Rec> {
    Int,
    String,
    Real,
    Term,
    Application(Box<[Rec]>),
    List,
    Placeholder,
    Blob,
    Long,
}

impl<Rec> TermPlaceholder<Rec> {
    pub fn cons_string(&self) -> &'static str {
        use TermPlaceholder::*;
        match *self {
            Int => "int",
            String => "string",
            Real => "real",
            Term => "term",
            Application(_) => "appl",
            List => "list",
            Placeholder => "placeholder",
            Blob => "blob",
            Long => "long",
        }
    }

    pub fn to_template<'s, F>(&self, factory: &'s F) -> Rec
    where
        F: ATermFactory<'s, ATermRef = Rec>,
        Rec: Clone + Borrow<<F as ATermFactory<'s>>::ATerm>,
    {
        use TermPlaceholder::*;
        match *self {
            Int | String | Real | Term | List | Placeholder | Blob | Long => {
                factory.application(self.cons_string(), ::std::iter::empty())
            }
            Application(ref args) => factory.application(self.cons_string(), args.iter().cloned()),
        }
    }
}

impl<AR> ::print::ATermWrite for TermPlaceholder<AR>
where
    AR: ::print::ATermWrite,
{
    fn to_ascii<W: ::std::fmt::Write>(&self, writer: &mut W) -> ::std::fmt::Result {
        use interface::TermPlaceholder::*;
        match *self {
            Int | String | Real | Term | List | Placeholder | Blob | Long => {
                write!(writer, "<{}>", self.cons_string())
            }
            Application(ref args) => {
                write!(writer, "<{}(", self.cons_string())?;
                (**args).to_ascii(writer)?;
                write!(writer, ")>")
            }
        }
    }
}