erl_dist 0.8.0

Rust Implementation of Erlang Distribution Protocol
Documentation
use crate::term::{Mfa, PidOrAtom};
use eetf::{Atom, DecodeError, FixInteger, List, Pid, Reference, Term, Tuple};

pub fn nil() -> Term {
    eetf::List::nil().into()
}

pub fn check_tuple_len(tuple: &Tuple, n: usize) -> Result<(), DecodeError> {
    if tuple.elements.len() != n {
        Err(DecodeError::UnexpectedType {
            value: tuple.clone().into(),
            expected: format!("{} elements tuple", n),
        })
    } else {
        Ok(())
    }
}

pub fn try_from_tagged_tuple3<T0, T1>(mut tuple: Tuple) -> Result<(T0, T1), DecodeError>
where
    T0: TryFromTerm,
    T1: TryFromTerm,
{
    check_tuple_len(&tuple, 3)?;
    Ok((
        T0::try_from_term(std::mem::replace(&mut tuple.elements[1], nil()))?,
        T1::try_from_term(std::mem::replace(&mut tuple.elements[2], nil()))?,
    ))
}

pub fn try_from_tagged_tuple4<T0, T1, T2>(mut tuple: Tuple) -> Result<(T0, T1, T2), DecodeError>
where
    T0: TryFromTerm,
    T1: TryFromTerm,
    T2: TryFromTerm,
{
    check_tuple_len(&tuple, 4)?;
    Ok((
        T0::try_from_term(std::mem::replace(&mut tuple.elements[1], nil()))?,
        T1::try_from_term(std::mem::replace(&mut tuple.elements[2], nil()))?,
        T2::try_from_term(std::mem::replace(&mut tuple.elements[3], nil()))?,
    ))
}

pub fn try_from_tagged_tuple5<T0, T1, T2, T3>(
    mut tuple: Tuple,
) -> Result<(T0, T1, T2, T3), DecodeError>
where
    T0: TryFromTerm,
    T1: TryFromTerm,
    T2: TryFromTerm,
    T3: TryFromTerm,
{
    check_tuple_len(&tuple, 5)?;
    Ok((
        T0::try_from_term(std::mem::replace(&mut tuple.elements[1], nil()))?,
        T1::try_from_term(std::mem::replace(&mut tuple.elements[2], nil()))?,
        T2::try_from_term(std::mem::replace(&mut tuple.elements[3], nil()))?,
        T3::try_from_term(std::mem::replace(&mut tuple.elements[4], nil()))?,
    ))
}

pub fn try_from_tagged_tuple6<T0, T1, T2, T3, T4>(
    mut tuple: Tuple,
) -> Result<(T0, T1, T2, T3, T4), DecodeError>
where
    T0: TryFromTerm,
    T1: TryFromTerm,
    T2: TryFromTerm,
    T3: TryFromTerm,
    T4: TryFromTerm,
{
    check_tuple_len(&tuple, 6)?;
    Ok((
        T0::try_from_term(std::mem::replace(&mut tuple.elements[1], nil()))?,
        T1::try_from_term(std::mem::replace(&mut tuple.elements[2], nil()))?,
        T2::try_from_term(std::mem::replace(&mut tuple.elements[3], nil()))?,
        T3::try_from_term(std::mem::replace(&mut tuple.elements[4], nil()))?,
        T4::try_from_term(std::mem::replace(&mut tuple.elements[5], nil()))?,
    ))
}

pub fn try_from_tagged_tuple7<T0, T1, T2, T3, T4, T5>(
    mut tuple: Tuple,
) -> Result<(T0, T1, T2, T3, T4, T5), DecodeError>
where
    T0: TryFromTerm,
    T1: TryFromTerm,
    T2: TryFromTerm,
    T3: TryFromTerm,
    T4: TryFromTerm,
    T5: TryFromTerm,
{
    check_tuple_len(&tuple, 7)?;
    Ok((
        T0::try_from_term(std::mem::replace(&mut tuple.elements[1], nil()))?,
        T1::try_from_term(std::mem::replace(&mut tuple.elements[2], nil()))?,
        T2::try_from_term(std::mem::replace(&mut tuple.elements[3], nil()))?,
        T3::try_from_term(std::mem::replace(&mut tuple.elements[4], nil()))?,
        T4::try_from_term(std::mem::replace(&mut tuple.elements[5], nil()))?,
        T5::try_from_term(std::mem::replace(&mut tuple.elements[6], nil()))?,
    ))
}

pub trait TryFromTerm: Sized {
    fn try_from_term(term: Term) -> Result<Self, DecodeError>;
}

impl TryFromTerm for Term {
    fn try_from_term(term: Term) -> Result<Self, DecodeError> {
        Ok(term)
    }
}

impl TryFromTerm for Pid {
    fn try_from_term(term: Term) -> Result<Self, DecodeError> {
        try_from_term(term, "pid")
    }
}

impl TryFromTerm for Atom {
    fn try_from_term(term: Term) -> Result<Self, DecodeError> {
        try_from_term(term, "atom")
    }
}

impl TryFromTerm for Reference {
    fn try_from_term(term: Term) -> Result<Self, DecodeError> {
        try_from_term(term, "reference")
    }
}

impl TryFromTerm for FixInteger {
    fn try_from_term(term: Term) -> Result<Self, DecodeError> {
        try_from_term(term, "integer")
    }
}

impl TryFromTerm for List {
    fn try_from_term(term: Term) -> Result<Self, DecodeError> {
        try_from_term(term, "list")
    }
}

impl TryFromTerm for PidOrAtom {
    fn try_from_term(term: Term) -> Result<Self, DecodeError> {
        term.try_into()
            .map(Self::Pid)
            .or_else(|term| term.try_into().map(Self::Atom))
            .map_err(|value| DecodeError::UnexpectedType {
                value,
                expected: "pid or atom".to_owned(),
            })
    }
}

impl TryFromTerm for Mfa {
    fn try_from_term(term: Term) -> Result<Self, DecodeError> {
        let mut tuple = try_from_term(term, "tuple")?;
        check_tuple_len(&tuple, 3)?;
        Ok(Self {
            module: TryFromTerm::try_from_term(std::mem::replace(&mut tuple.elements[0], nil()))?,
            function: TryFromTerm::try_from_term(std::mem::replace(&mut tuple.elements[1], nil()))?,
            arity: TryFromTerm::try_from_term(std::mem::replace(&mut tuple.elements[2], nil()))?,
        })
    }
}

pub fn try_from_term<T>(term: Term, expected: &str) -> Result<T, DecodeError>
where
    Term: TryInto<T, Error = Term>,
{
    term.try_into()
        .map_err(|value| DecodeError::UnexpectedType {
            value,
            expected: expected.to_owned(),
        })
}