eetf 0.8.0

Library for encoding/decoding Erlang External Term Format
Documentation
#![allow(clippy::type_complexity)]

use super::*;
use crate::convert::AsOption;
use crate::convert::TryAsRef;
use num::bigint::ToBigInt;
use num::bigint::ToBigUint;
use num::traits::ToPrimitive;
use std::fmt::Debug;

pub type Result<'a, T> = std::result::Result<T, Unmatch<'a>>;

pub trait Pattern<'a>: Debug + Clone {
    type Output;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output>;

    fn unmatched(&self, input: &'a Term) -> Unmatch<'a>
    where
        Self: 'static,
    {
        Unmatch {
            input,
            pattern: Box::new(self.clone()),
            cause: None,
        }
    }
}

#[derive(Debug)]
pub struct Unmatch<'a> {
    pub input: &'a Term,
    pub pattern: Box<dyn Debug>,
    pub cause: Option<Box<Unmatch<'a>>>,
}
impl<'a> Unmatch<'a> {
    pub fn cause(mut self, cause: Unmatch<'a>) -> Self {
        self.cause = Some(Box::new(cause));
        self
    }
    pub fn depth(&self) -> usize {
        let mut depth = 0;
        let mut curr = &self.cause;
        while let Some(ref next) = *curr {
            depth += 1;
            curr = &next.cause;
        }
        depth
    }
    pub fn max_depth(self, other: Self) -> Self {
        if self.depth() < other.depth() {
            other
        } else {
            self
        }
    }
}

#[derive(Debug, Clone)]
pub enum Union2<A, B> {
    A(A),
    B(B),
}
impl<A, B> Union2<A, B> {
    pub fn is_a(&self) -> bool {
        matches!(*self, Union2::A(_))
    }
    pub fn is_b(&self) -> bool {
        matches!(*self, Union2::B(_))
    }
    pub fn into_result(self) -> ::std::result::Result<A, B> {
        match self {
            Union2::A(x) => Ok(x),
            Union2::B(x) => Err(x),
        }
    }
}

#[derive(Debug, Clone)]
pub enum Union3<A, B, C> {
    A(A),
    B(B),
    C(C),
}

#[derive(Debug, Clone)]
pub enum Union4<A, B, C, D> {
    A(A),
    B(B),
    C(C),
    D(D),
}

#[derive(Debug, Clone)]
pub enum Union5<A, B, C, D, E> {
    A(A),
    B(B),
    C(C),
    D(D),
    E(E),
}

#[derive(Debug, Clone)]
pub enum Union6<A, B, C, D, E, F> {
    A(A),
    B(B),
    C(C),
    D(D),
    E(E),
    F(F),
}

#[derive(Debug, Clone)]
pub struct Any<T>(::std::marker::PhantomData<T>);
impl<T> Any<T>
where
    T: Debug,
{
    pub fn new() -> Self {
        Any(::std::marker::PhantomData)
    }
}
impl<T> Default for Any<T>
where
    T: Debug,
{
    fn default() -> Self {
        Self::new()
    }
}
pub fn any<T>() -> Any<T>
where
    T: Debug,
{
    Any::new()
}
impl<'a, O> Pattern<'a> for Any<O>
where
    O: Debug + Clone + 'static,
    Term: TryAsRef<O>,
{
    type Output = &'a O;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        input.try_as_ref().ok_or_else(|| self.unmatched(input))
    }
}

impl<'a> Pattern<'a> for &'static str {
    type Output = Self;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let a: &Atom = input.try_as_ref().ok_or_else(|| self.unmatched(input))?;
        (*self == a.name)
            .as_option()
            .ok_or_else(|| self.unmatched(input))?;
        Ok(*self)
    }
}

#[derive(Debug, Clone)]
pub struct VarList<P>(pub P);
impl<'a, P> Pattern<'a> for VarList<P>
where
    P: Pattern<'a> + 'static,
{
    type Output = Vec<P::Output>;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let l: &List = input.try_as_ref().ok_or_else(|| self.unmatched(input))?;
        let mut outputs = Vec::with_capacity(l.elements.len());
        for e in &l.elements {
            outputs.push(
                self.0
                    .try_match(e)
                    .map_err(|e| self.unmatched(input).cause(e))?,
            );
        }
        Ok(outputs)
    }
}

#[derive(Debug, Clone)]
pub struct FixList<T>(pub T);
impl<'a, P0> Pattern<'a> for FixList<(P0,)>
where
    P0: Pattern<'a> + 'static,
{
    type Output = P0::Output;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let l: &List = input.try_as_ref().ok_or_else(|| self.unmatched(input))?;
        let e = &l.elements;
        (e.len() == 1)
            .as_option()
            .ok_or_else(|| self.unmatched(input))?;
        let o0 = (self.0)
            .0
            .try_match(&e[0])
            .map_err(|e| self.unmatched(input).cause(e))?;
        Ok(o0)
    }
}

impl<'a, P0, P1> Pattern<'a> for FixList<(P0, P1)>
where
    P0: Pattern<'a> + 'static,
    P1: Pattern<'a> + 'static,
{
    type Output = (P0::Output, P1::Output);
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let l: &List = input.try_as_ref().ok_or_else(|| self.unmatched(input))?;
        let e = &l.elements;
        (e.len() == 2)
            .as_option()
            .ok_or_else(|| self.unmatched(input))?;
        let o0 = (self.0)
            .0
            .try_match(&e[0])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o1 = (self.0)
            .1
            .try_match(&e[1])
            .map_err(|e| self.unmatched(input).cause(e))?;
        Ok((o0, o1))
    }
}

impl<'a, P0, P1, P2> Pattern<'a> for FixList<(P0, P1, P2)>
where
    P0: Pattern<'a> + 'static,
    P1: Pattern<'a> + 'static,
    P2: Pattern<'a> + 'static,
{
    type Output = (P0::Output, P1::Output, P2::Output);
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let l: &List = input.try_as_ref().ok_or_else(|| self.unmatched(input))?;
        let e = &l.elements;
        (e.len() == 3)
            .as_option()
            .ok_or_else(|| self.unmatched(input))?;
        let o0 = (self.0)
            .0
            .try_match(&e[0])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o1 = (self.0)
            .1
            .try_match(&e[1])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o2 = (self.0)
            .2
            .try_match(&e[2])
            .map_err(|e| self.unmatched(input).cause(e))?;
        Ok((o0, o1, o2))
    }
}

impl<'a, P0, P1, P2, P3> Pattern<'a> for FixList<(P0, P1, P2, P3)>
where
    P0: Pattern<'a> + 'static,
    P1: Pattern<'a> + 'static,
    P2: Pattern<'a> + 'static,
    P3: Pattern<'a> + 'static,
{
    type Output = (P0::Output, P1::Output, P2::Output, P3::Output);
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let l: &List = input.try_as_ref().ok_or_else(|| self.unmatched(input))?;
        let e = &l.elements;
        (e.len() == 4)
            .as_option()
            .ok_or_else(|| self.unmatched(input))?;
        let o0 = (self.0)
            .0
            .try_match(&e[0])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o1 = (self.0)
            .1
            .try_match(&e[1])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o2 = (self.0)
            .2
            .try_match(&e[2])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o3 = (self.0)
            .3
            .try_match(&e[3])
            .map_err(|e| self.unmatched(input).cause(e))?;
        Ok((o0, o1, o2, o3))
    }
}

impl<'a, P0, P1, P2, P3, P4> Pattern<'a> for FixList<(P0, P1, P2, P3, P4)>
where
    P0: Pattern<'a> + 'static,
    P1: Pattern<'a> + 'static,
    P2: Pattern<'a> + 'static,
    P3: Pattern<'a> + 'static,
    P4: Pattern<'a> + 'static,
{
    type Output = (P0::Output, P1::Output, P2::Output, P3::Output, P4::Output);
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let l: &List = input.try_as_ref().ok_or_else(|| self.unmatched(input))?;
        let e = &l.elements;
        (e.len() == 5)
            .as_option()
            .ok_or_else(|| self.unmatched(input))?;
        let o0 = (self.0)
            .0
            .try_match(&e[0])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o1 = (self.0)
            .1
            .try_match(&e[1])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o2 = (self.0)
            .2
            .try_match(&e[2])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o3 = (self.0)
            .3
            .try_match(&e[3])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o4 = (self.0)
            .4
            .try_match(&e[4])
            .map_err(|e| self.unmatched(input).cause(e))?;
        Ok((o0, o1, o2, o3, o4))
    }
}

impl<'a, P0, P1, P2, P3, P4, P5> Pattern<'a> for FixList<(P0, P1, P2, P3, P4, P5)>
where
    P0: Pattern<'a> + 'static,
    P1: Pattern<'a> + 'static,
    P2: Pattern<'a> + 'static,
    P3: Pattern<'a> + 'static,
    P4: Pattern<'a> + 'static,
    P5: Pattern<'a> + 'static,
{
    type Output = (
        P0::Output,
        P1::Output,
        P2::Output,
        P3::Output,
        P4::Output,
        P5::Output,
    );
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let l: &List = input.try_as_ref().ok_or_else(|| self.unmatched(input))?;
        let e = &l.elements;
        (e.len() == 6)
            .as_option()
            .ok_or_else(|| self.unmatched(input))?;
        let o0 = (self.0)
            .0
            .try_match(&e[0])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o1 = (self.0)
            .1
            .try_match(&e[1])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o2 = (self.0)
            .2
            .try_match(&e[2])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o3 = (self.0)
            .3
            .try_match(&e[3])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o4 = (self.0)
            .4
            .try_match(&e[4])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o5 = (self.0)
            .5
            .try_match(&e[5])
            .map_err(|e| self.unmatched(input).cause(e))?;
        Ok((o0, o1, o2, o3, o4, o5))
    }
}

#[derive(Debug, Clone)]
pub struct Nil;
impl<'a> Pattern<'a> for Nil {
    type Output = &'a [Term];
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let l: &List = input.try_as_ref().ok_or_else(|| self.unmatched(input))?;
        l.elements
            .is_empty()
            .as_option()
            .ok_or_else(|| self.unmatched(input))?;
        Ok(&l.elements)
    }
}

#[derive(Debug, Clone)]
pub struct Cons<H, T>(pub H, pub T);
impl<'a, P0, P1> Pattern<'a> for Cons<P0, P1>
where
    P0: Pattern<'a> + 'static,
    P1: Pattern<'a> + 'static,
{
    type Output = (P0::Output, Vec<P1::Output>);
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let l: &List = input.try_as_ref().ok_or_else(|| self.unmatched(input))?;
        let e = &l.elements;
        (!e.is_empty())
            .as_option()
            .ok_or_else(|| self.unmatched(input))?;
        let h = self
            .0
            .try_match(&e[0])
            .map_err(|e| self.unmatched(input).cause(e))?;

        let mut tail = Vec::with_capacity(l.elements.len() - 1);
        for e in &l.elements[1..] {
            tail.push(
                self.1
                    .try_match(e)
                    .map_err(|e| self.unmatched(input).cause(e))?,
            );
        }
        Ok((h, tail))
    }
}

impl<'a> Pattern<'a> for () {
    type Output = ();
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let t: &Tuple = input.try_as_ref().ok_or_else(|| self.unmatched(input))?;
        t.elements
            .is_empty()
            .as_option()
            .ok_or_else(|| self.unmatched(input))?;
        Ok(())
    }
}

impl<'a, P0> Pattern<'a> for (P0,)
where
    P0: Pattern<'a> + 'static,
{
    type Output = P0::Output;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let t: &Tuple = input.try_as_ref().ok_or_else(|| self.unmatched(input))?;
        (t.elements.len() == 1)
            .as_option()
            .ok_or_else(|| self.unmatched(input))?;
        let o0 = self
            .0
            .try_match(&t.elements[0])
            .map_err(|e| self.unmatched(input).cause(e))?;
        Ok(o0)
    }
}

impl<'a, P0, P1> Pattern<'a> for (P0, P1)
where
    P0: Pattern<'a> + 'static,
    P1: Pattern<'a> + 'static,
{
    type Output = (P0::Output, P1::Output);
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let t: &Tuple = input.try_as_ref().ok_or_else(|| self.unmatched(input))?;
        let e = &t.elements;
        (e.len() == 2)
            .as_option()
            .ok_or_else(|| self.unmatched(input))?;
        let o0 = self
            .0
            .try_match(&e[0])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o1 = self
            .1
            .try_match(&e[1])
            .map_err(|e| self.unmatched(input).cause(e))?;
        Ok((o0, o1))
    }
}

impl<'a, P0, P1, P2> Pattern<'a> for (P0, P1, P2)
where
    P0: Pattern<'a> + 'static,
    P1: Pattern<'a> + 'static,
    P2: Pattern<'a> + 'static,
{
    type Output = (P0::Output, P1::Output, P2::Output);
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let t: &Tuple = input.try_as_ref().ok_or_else(|| self.unmatched(input))?;
        let e = &t.elements;
        (e.len() == 3)
            .as_option()
            .ok_or_else(|| self.unmatched(input))?;
        let o0 = self
            .0
            .try_match(&e[0])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o1 = self
            .1
            .try_match(&e[1])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o2 = self
            .2
            .try_match(&e[2])
            .map_err(|e| self.unmatched(input).cause(e))?;
        Ok((o0, o1, o2))
    }
}

impl<'a, P0, P1, P2, P3> Pattern<'a> for (P0, P1, P2, P3)
where
    P0: Pattern<'a> + 'static,
    P1: Pattern<'a> + 'static,
    P2: Pattern<'a> + 'static,
    P3: Pattern<'a> + 'static,
{
    type Output = (P0::Output, P1::Output, P2::Output, P3::Output);
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let t: &Tuple = input.try_as_ref().ok_or_else(|| self.unmatched(input))?;
        let e = &t.elements;
        (e.len() == 4)
            .as_option()
            .ok_or_else(|| self.unmatched(input))?;
        let o0 = self
            .0
            .try_match(&e[0])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o1 = self
            .1
            .try_match(&e[1])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o2 = self
            .2
            .try_match(&e[2])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o3 = self
            .3
            .try_match(&e[3])
            .map_err(|e| self.unmatched(input).cause(e))?;
        Ok((o0, o1, o2, o3))
    }
}

impl<'a, P0, P1, P2, P3, P4> Pattern<'a> for (P0, P1, P2, P3, P4)
where
    P0: Pattern<'a> + 'static,
    P1: Pattern<'a> + 'static,
    P2: Pattern<'a> + 'static,
    P3: Pattern<'a> + 'static,
    P4: Pattern<'a> + 'static,
{
    type Output = (P0::Output, P1::Output, P2::Output, P3::Output, P4::Output);
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let t: &Tuple = input.try_as_ref().ok_or_else(|| self.unmatched(input))?;
        let e = &t.elements;
        (e.len() == 5)
            .as_option()
            .ok_or_else(|| self.unmatched(input))?;
        let o0 = self
            .0
            .try_match(&e[0])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o1 = self
            .1
            .try_match(&e[1])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o2 = self
            .2
            .try_match(&e[2])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o3 = self
            .3
            .try_match(&e[3])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o4 = self
            .4
            .try_match(&e[4])
            .map_err(|e| self.unmatched(input).cause(e))?;
        Ok((o0, o1, o2, o3, o4))
    }
}

impl<'a, P0, P1, P2, P3, P4, P5> Pattern<'a> for (P0, P1, P2, P3, P4, P5)
where
    P0: Pattern<'a> + 'static,
    P1: Pattern<'a> + 'static,
    P2: Pattern<'a> + 'static,
    P3: Pattern<'a> + 'static,
    P4: Pattern<'a> + 'static,
    P5: Pattern<'a> + 'static,
{
    type Output = (
        P0::Output,
        P1::Output,
        P2::Output,
        P3::Output,
        P4::Output,
        P5::Output,
    );
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let t: &Tuple = input.try_as_ref().ok_or_else(|| self.unmatched(input))?;
        let e = &t.elements;
        (e.len() == 6)
            .as_option()
            .ok_or_else(|| self.unmatched(input))?;
        let o0 = self
            .0
            .try_match(&e[0])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o1 = self
            .1
            .try_match(&e[1])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o2 = self
            .2
            .try_match(&e[2])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o3 = self
            .3
            .try_match(&e[3])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o4 = self
            .4
            .try_match(&e[4])
            .map_err(|e| self.unmatched(input).cause(e))?;
        let o5 = self
            .5
            .try_match(&e[5])
            .map_err(|e| self.unmatched(input).cause(e))?;
        Ok((o0, o1, o2, o3, o4, o5))
    }
}

macro_rules! try_err {
    ($e:expr) => {
        match $e {
            Ok(value) => return Ok(value),
            Err(err) => err,
        }
    };
}

#[derive(Debug, Clone)]
pub struct Or<T>(pub T);
impl<'a, P0, P1> Pattern<'a> for Or<(P0, P1)>
where
    P0: Pattern<'a> + 'static,
    P1: Pattern<'a> + 'static,
{
    type Output = Union2<P0::Output, P1::Output>;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let e = try_err!((self.0).0.try_match(input).map(Union2::A));
        let e = try_err!((self.0).1.try_match(input).map(Union2::B)).max_depth(e);
        Err(self.unmatched(input).cause(e))
    }
}
impl<'a, P0, P1, P2> Pattern<'a> for Or<(P0, P1, P2)>
where
    P0: Pattern<'a> + 'static,
    P1: Pattern<'a> + 'static,
    P2: Pattern<'a> + 'static,
{
    type Output = Union3<P0::Output, P1::Output, P2::Output>;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let e = try_err!((self.0).0.try_match(input).map(Union3::A));
        let e = try_err!((self.0).1.try_match(input).map(Union3::B)).max_depth(e);
        let e = try_err!((self.0).2.try_match(input).map(Union3::C)).max_depth(e);
        Err(self.unmatched(input).cause(e))
    }
}
impl<'a, P0, P1, P2, P3> Pattern<'a> for Or<(P0, P1, P2, P3)>
where
    P0: Pattern<'a> + 'static,
    P1: Pattern<'a> + 'static,
    P2: Pattern<'a> + 'static,
    P3: Pattern<'a> + 'static,
{
    type Output = Union4<P0::Output, P1::Output, P2::Output, P3::Output>;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let e = try_err!((self.0).0.try_match(input).map(Union4::A));
        let e = try_err!((self.0).1.try_match(input).map(Union4::B)).max_depth(e);
        let e = try_err!((self.0).2.try_match(input).map(Union4::C)).max_depth(e);
        let e = try_err!((self.0).3.try_match(input).map(Union4::D)).max_depth(e);
        Err(self.unmatched(input).cause(e))
    }
}
impl<'a, P0, P1, P2, P3, P4> Pattern<'a> for Or<(P0, P1, P2, P3, P4)>
where
    P0: Pattern<'a> + 'static,
    P1: Pattern<'a> + 'static,
    P2: Pattern<'a> + 'static,
    P3: Pattern<'a> + 'static,
    P4: Pattern<'a> + 'static,
{
    type Output = Union5<P0::Output, P1::Output, P2::Output, P3::Output, P4::Output>;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let e = try_err!((self.0).0.try_match(input).map(Union5::A));
        let e = try_err!((self.0).1.try_match(input).map(Union5::B)).max_depth(e);
        let e = try_err!((self.0).2.try_match(input).map(Union5::C)).max_depth(e);
        let e = try_err!((self.0).3.try_match(input).map(Union5::D)).max_depth(e);
        let e = try_err!((self.0).4.try_match(input).map(Union5::E)).max_depth(e);
        Err(self.unmatched(input).cause(e))
    }
}
impl<'a, P0, P1, P2, P3, P4, P5> Pattern<'a> for Or<(P0, P1, P2, P3, P4, P5)>
where
    P0: Pattern<'a> + 'static,
    P1: Pattern<'a> + 'static,
    P2: Pattern<'a> + 'static,
    P3: Pattern<'a> + 'static,
    P4: Pattern<'a> + 'static,
    P5: Pattern<'a> + 'static,
{
    type Output = Union6<P0::Output, P1::Output, P2::Output, P3::Output, P4::Output, P5::Output>;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let e = try_err!((self.0).0.try_match(input).map(Union6::A));
        let e = try_err!((self.0).1.try_match(input).map(Union6::B)).max_depth(e);
        let e = try_err!((self.0).2.try_match(input).map(Union6::C)).max_depth(e);
        let e = try_err!((self.0).3.try_match(input).map(Union6::D)).max_depth(e);
        let e = try_err!((self.0).4.try_match(input).map(Union6::E)).max_depth(e);
        let e = try_err!((self.0).5.try_match(input).map(Union6::F)).max_depth(e);
        Err(self.unmatched(input).cause(e))
    }
}

#[derive(Debug, Clone)]
pub struct Ascii;
impl<'a> Pattern<'a> for Ascii {
    type Output = char;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let n = input.to_u8().ok_or_else(|| self.unmatched(input))?;
        if n < 0x80 {
            Ok(n as char)
        } else {
            Err(self.unmatched(input))
        }
    }
}

#[derive(Debug, Clone)]
pub struct Unicode;
impl<'a> Pattern<'a> for Unicode {
    type Output = char;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let n = input.to_u32().ok_or_else(|| self.unmatched(input))?;
        ::std::char::from_u32(n).ok_or_else(|| self.unmatched(input))
    }
}

#[derive(Debug, Clone)]
pub struct Str<C>(pub C);
impl<'a, C> Pattern<'a> for Str<C>
where
    C: Pattern<'a, Output = char> + 'static,
{
    type Output = String;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        let l: &List = input.try_as_ref().ok_or_else(|| self.unmatched(input))?;
        let mut s = String::with_capacity(l.elements.len());
        for e in &l.elements {
            let c = self
                .0
                .try_match(e)
                .map_err(|e| self.unmatched(input).cause(e))?;
            s.push(c);
        }
        Ok(s)
    }
}

#[derive(Debug, Clone)]
pub struct U8;
impl<'a> Pattern<'a> for U8 {
    type Output = u8;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        input.to_u8().ok_or_else(|| self.unmatched(input))
    }
}

#[derive(Debug, Clone)]
pub struct I8;
impl<'a> Pattern<'a> for I8 {
    type Output = i8;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        input.to_i8().ok_or_else(|| self.unmatched(input))
    }
}

#[derive(Debug, Clone)]
pub struct U16;
impl<'a> Pattern<'a> for U16 {
    type Output = u16;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        input.to_u16().ok_or_else(|| self.unmatched(input))
    }
}

#[derive(Debug, Clone)]
pub struct I16;
impl<'a> Pattern<'a> for I16 {
    type Output = i16;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        input.to_i16().ok_or_else(|| self.unmatched(input))
    }
}

#[derive(Debug, Clone)]
pub struct U32;
impl<'a> Pattern<'a> for U32 {
    type Output = u32;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        input.to_u32().ok_or_else(|| self.unmatched(input))
    }
}

#[derive(Debug, Clone)]
pub struct I32;
impl<'a> Pattern<'a> for I32 {
    type Output = i32;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        input.to_i32().ok_or_else(|| self.unmatched(input))
    }
}

#[derive(Debug, Clone)]
pub struct U64;
impl<'a> Pattern<'a> for U64 {
    type Output = u64;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        input.to_u64().ok_or_else(|| self.unmatched(input))
    }
}

#[derive(Debug, Clone)]
pub struct I64;
impl<'a> Pattern<'a> for I64 {
    type Output = i64;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        input.to_i64().ok_or_else(|| self.unmatched(input))
    }
}

#[derive(Debug, Clone)]
pub struct Int;
impl<'a> Pattern<'a> for Int {
    type Output = num::BigInt;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        input.to_bigint().ok_or_else(|| self.unmatched(input))
    }
}

#[derive(Debug, Clone)]
pub struct Uint;
impl<'a> Pattern<'a> for Uint {
    type Output = num::BigUint;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        input.to_biguint().ok_or_else(|| self.unmatched(input))
    }
}

#[derive(Debug, Clone)]
pub struct F32;
impl<'a> Pattern<'a> for F32 {
    type Output = f32;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        input.to_f32().ok_or_else(|| self.unmatched(input))
    }
}

#[derive(Debug, Clone)]
pub struct F64;
impl<'a> Pattern<'a> for F64 {
    type Output = f64;
    fn try_match(&self, input: &'a Term) -> Result<'a, Self::Output> {
        input.to_f64().ok_or_else(|| self.unmatched(input))
    }
}