1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
use {types, wrapper, Encoder, Env, Term};

/// Represents usual errors that can happen in a nif. This enables you
/// to return an error from anywhere, even places where you don't have
/// an Env availible.
pub enum Error {
    /// Returned when the NIF has been called with the wrong number or type of
    /// arguments.
    BadArg,
    /// Encodes the string into an atom and returns it from the NIF.
    Atom(&'static str),
    RaiseAtom(&'static str),
    RaiseTerm(Box<Encoder>),
}

impl Error {
    /// # Unsafe
    ///
    /// If `self` is a `BadArg`, `RaiseAtom`, or `RaiseTerm` value, then the
    /// term returned from this method must not be used except as the return
    /// value from the calling NIF.
    pub unsafe fn encode<'a>(self, env: Env<'a>) -> Term<'a> {
        match self {
            Error::BadArg => {
                let exception = wrapper::exception::raise_badarg(env.as_c_arg());
                Term::new(env, exception)
            }
            Error::Atom(atom_str) => types::atom::Atom::from_str(env, atom_str)
                .ok()
                .expect("Error::Atom: bad atom")
                .to_term(env),
            Error::RaiseAtom(atom_str) => {
                let atom = types::atom::Atom::from_str(env, atom_str)
                    .ok()
                    .expect("Error::RaiseAtom: bad argument");
                let exception =
                    wrapper::exception::raise_exception(env.as_c_arg(), atom.as_c_arg());
                Term::new(env, exception)
            }
            Error::RaiseTerm(ref term_unencoded) => {
                let term = term_unencoded.encode(env);
                let exception =
                    wrapper::exception::raise_exception(env.as_c_arg(), term.as_c_arg());
                Term::new(env, exception)
            }
        }
    }
}