#[cfg(feature = "bigint")]
#[cfg_attr(docsrs, doc(cfg(feature = "bigint")))]
mod bigint;
mod bool;
mod float;
mod integer;
mod list;
mod map;
mod string;
mod tuple;
use crate::types::{
AnyTerm, Atom, Binary, Bitstring, Env, Float, Fun, Integer, List, LocalPid, LocalPort, Map, Pid,
Port, Raised, Reference, Term, Tuple, TupleView, TypedTerm, THE_NON_VALUE,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CodecError {
WrongType,
IntegerOverflow,
NotFinite,
FloatRange,
NotUtf8,
WrongArity,
UnknownTermType,
}
impl std::fmt::Display for CodecError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CodecError::WrongType => write!(f, "wrong term type"),
CodecError::IntegerOverflow => write!(f, "integer overflow"),
CodecError::NotFinite => write!(f, "float is not finite"),
CodecError::FloatRange => write!(f, "float out of range"),
CodecError::NotUtf8 => write!(f, "not valid UTF-8"),
CodecError::WrongArity => write!(f, "wrong tuple arity"),
CodecError::UnknownTermType => write!(f, "unknown term type"),
}
}
}
impl std::error::Error for CodecError {}
pub trait Encoder<'id> {
fn encode(&self, env: impl Env<'id>) -> Result<AnyTerm<'id>, CodecError>;
}
impl<'id, T: Encoder<'id>> Encoder<'id> for Result<T, Raised<'id>> {
fn encode(&self, env: impl Env<'id>) -> Result<AnyTerm<'id>, CodecError> {
match self {
Ok(v) => v.encode(env),
Err(_) => Ok(AnyTerm::wrap(THE_NON_VALUE, env)),
}
}
}
pub trait Decoder<'id>: Sized {
fn decode(term: AnyTerm<'id>, env: impl Env<'id>) -> Result<Self, CodecError>;
}
impl<'id> Decoder<'id> for AnyTerm<'id> {
fn decode(term: AnyTerm<'id>, _env: impl Env<'id>) -> Result<Self, CodecError> {
Ok(term)
}
}
macro_rules! encode_by_wrap {
($($t:ty),+ $(,)?) => { $(
impl<'id> Encoder<'id> for $t {
fn encode(&self, env: impl Env<'id>) -> Result<AnyTerm<'id>, CodecError> {
Ok(AnyTerm::wrap(Term::raw_term(*self), env))
}
}
)+ };
}
encode_by_wrap!(
AnyTerm<'id>, Integer<'id>, Float<'id>, Reference<'id>, Fun<'id>, Tuple<'id>, List<'id>,
Map<'id>, Binary<'id>, Bitstring<'id>, Pid<'id>, Port<'id>, TupleView<'id>, Atom, LocalPid,
LocalPort,
);
impl<'id> Encoder<'id> for TypedTerm<'id> {
fn encode(&self, env: impl Env<'id>) -> Result<AnyTerm<'id>, CodecError> {
Ok(AnyTerm::wrap((*self).raw_term(), env))
}
}
impl<'id> Decoder<'id> for Integer<'id> {
fn decode(term: AnyTerm<'id>, env: impl Env<'id>) -> Result<Self, CodecError> {
if env.term_type(term) == Some(enif_ffi::TermType::Integer) {
Ok(Integer::from_raw(term.raw_term()))
} else {
Err(CodecError::WrongType)
}
}
}
impl<'id> Decoder<'id> for Float<'id> {
fn decode(term: AnyTerm<'id>, env: impl Env<'id>) -> Result<Self, CodecError> {
if env.term_type(term) == Some(enif_ffi::TermType::Float) {
Ok(Float::from_raw(term.raw_term()))
} else {
Err(CodecError::WrongType)
}
}
}
impl<'id> Decoder<'id> for Bitstring<'id> {
fn decode(term: AnyTerm<'id>, env: impl Env<'id>) -> Result<Self, CodecError> {
if env.term_type(term) == Some(enif_ffi::TermType::Bitstring) {
Ok(Bitstring::from_raw(term.raw_term()))
} else {
Err(CodecError::WrongType)
}
}
}
impl<'id> Decoder<'id> for Reference<'id> {
fn decode(term: AnyTerm<'id>, env: impl Env<'id>) -> Result<Self, CodecError> {
if Reference::is_ref(env, term) {
Ok(Reference::from_raw(term.raw_term()))
} else {
Err(CodecError::WrongType)
}
}
}
impl<'id> Decoder<'id> for Fun<'id> {
fn decode(term: AnyTerm<'id>, env: impl Env<'id>) -> Result<Self, CodecError> {
if Fun::is_fun(env, term) {
Ok(Fun::from_raw(term.raw_term()))
} else {
Err(CodecError::WrongType)
}
}
}
impl<'id> Decoder<'id> for Tuple<'id> {
fn decode(term: AnyTerm<'id>, env: impl Env<'id>) -> Result<Self, CodecError> {
if Tuple::is_tuple(env, term) {
Ok(Tuple::from_raw(term.raw_term()))
} else {
Err(CodecError::WrongType)
}
}
}
impl<'id> Decoder<'id> for List<'id> {
fn decode(term: AnyTerm<'id>, env: impl Env<'id>) -> Result<Self, CodecError> {
if List::is_list(env, term) {
Ok(List::from_raw(term.raw_term()))
} else {
Err(CodecError::WrongType)
}
}
}
impl<'id> Decoder<'id> for Map<'id> {
fn decode(term: AnyTerm<'id>, env: impl Env<'id>) -> Result<Self, CodecError> {
if Map::is_map(env, term) {
Ok(Map::from_raw(term.raw_term()))
} else {
Err(CodecError::WrongType)
}
}
}
impl<'id> Decoder<'id> for Binary<'id> {
fn decode(term: AnyTerm<'id>, env: impl Env<'id>) -> Result<Self, CodecError> {
if Binary::is_binary(env, term) {
Ok(Binary::from_raw(term.raw_term()))
} else {
Err(CodecError::WrongType)
}
}
}
impl<'id> Decoder<'id> for Pid<'id> {
fn decode(term: AnyTerm<'id>, env: impl Env<'id>) -> Result<Self, CodecError> {
if Pid::is_pid(env, term) {
Ok(Pid::from_raw(term.raw_term()))
} else {
Err(CodecError::WrongType)
}
}
}
impl<'id> Decoder<'id> for Port<'id> {
fn decode(term: AnyTerm<'id>, env: impl Env<'id>) -> Result<Self, CodecError> {
if Port::is_port(env, term) {
Ok(Port::from_raw(term.raw_term()))
} else {
Err(CodecError::WrongType)
}
}
}
impl<'id> Decoder<'id> for Atom {
fn decode(term: AnyTerm<'id>, env: impl Env<'id>) -> Result<Self, CodecError> {
if Atom::is_atom(env, term) {
Ok(Atom::from_raw(term.raw_term()))
} else {
Err(CodecError::WrongType)
}
}
}
impl<'id> Decoder<'id> for LocalPid {
fn decode(term: AnyTerm<'id>, env: impl Env<'id>) -> Result<Self, CodecError> {
Pid::from_raw(term.raw_term()).to_local(env).ok_or(CodecError::WrongType)
}
}
impl<'id> Decoder<'id> for LocalPort {
fn decode(term: AnyTerm<'id>, env: impl Env<'id>) -> Result<Self, CodecError> {
Port::from_raw(term.raw_term()).to_local(env).ok_or(CodecError::WrongType)
}
}
impl<'id> Decoder<'id> for TypedTerm<'id> {
fn decode(term: AnyTerm<'id>, env: impl Env<'id>) -> Result<Self, CodecError> {
term.resolve(env).ok_or(CodecError::UnknownTermType)
}
}