Skip to main content

otter/types/terms/
fun.rs

1//! [`Fun`] — an opaque handle to an Erlang fun (closure or function reference).
2//! The NIF API exposes no inspection; a fun can only be held and passed back.
3
4use core::marker::PhantomData;
5
6use crate::types::sealed::Sealed;
7use crate::types::{Env, Invariant, RawTerm, Term};
8
9/// An Erlang fun (closure or function reference).
10///
11/// The NIF API provides no inspection of fun contents. A `Fun` can only be
12/// held and passed back to Erlang, or used as an argument to `apply`.
13#[derive(Clone, Copy)]
14pub struct Fun<'id> {
15    raw_term: RawTerm,
16    _id: Invariant<'id>,
17}
18
19impl<'id> Fun<'id> {
20    #[crate::raw]
21    pub(crate) fn from_raw(raw_term: RawTerm) -> Self {
22        Self { raw_term, _id: PhantomData }
23    }
24
25    /// Returns `true` if `term` is a fun (`enif_is_fun`).
26    pub fn is_fun(env: impl Env<'id>, term: impl Term<'id>) -> bool {
27        unsafe { enif_ffi::is_fun(env.raw_env(), term.raw_term()) != 0 }
28    }
29}
30
31impl<'id> Sealed for Fun<'id> {}
32
33impl<'id> Term<'id> for Fun<'id> {
34    fn raw_term(self) -> RawTerm {
35        self.raw_term
36    }
37}
38
39impl PartialEq for Fun<'_> {
40    fn eq(&self, other: &Self) -> bool {
41        unsafe { enif_ffi::is_identical(self.raw_term, other.raw_term) != 0 }
42    }
43}
44
45impl Eq for Fun<'_> {}
46
47impl PartialOrd for Fun<'_> {
48    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
49        Some(self.cmp(other))
50    }
51}
52
53impl Ord for Fun<'_> {
54    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
55        let c = unsafe { enif_ffi::compare(self.raw_term, other.raw_term) };
56        c.cmp(&0)
57    }
58}
59
60impl std::fmt::Debug for Fun<'_> {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        write!(f, "Fun")
63    }
64}