use beamr::native::NativeFn;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Determinism {
Pure,
SideEffectful,
}
#[derive(Clone, Debug)]
pub struct Nif {
module: String,
function: String,
arity: u8,
native: NativeFn,
dirty: bool,
determinism: Determinism,
}
impl Nif {
#[must_use]
pub(crate) fn new(
module: impl Into<String>,
function: impl Into<String>,
arity: u8,
native: NativeFn,
dirty: bool,
determinism: Determinism,
) -> Self {
Self {
module: module.into(),
function: function.into(),
arity,
native,
dirty,
determinism,
}
}
#[must_use]
pub fn pure(
module: impl Into<String>,
function: impl Into<String>,
arity: u8,
native: NativeFn,
) -> Self {
Self::new(module, function, arity, native, false, Determinism::Pure)
}
#[must_use]
pub fn side_effectful(
module: impl Into<String>,
function: impl Into<String>,
arity: u8,
native: NativeFn,
) -> Self {
Self::new(
module,
function,
arity,
native,
true,
Determinism::SideEffectful,
)
}
#[must_use]
pub fn module(&self) -> &str {
&self.module
}
#[must_use]
pub fn function(&self) -> &str {
&self.function
}
#[must_use]
pub const fn arity(&self) -> u8 {
self.arity
}
#[must_use]
pub const fn native(&self) -> NativeFn {
self.native
}
#[must_use]
pub const fn is_dirty(&self) -> bool {
self.dirty
}
#[must_use]
pub const fn determinism(&self) -> Determinism {
self.determinism
}
}
#[cfg(test)]
mod tests {
use beamr::{native::ProcessContext, term::Term};
use super::{Determinism, Nif};
fn identity_native(args: &[Term], ctx: &mut ProcessContext) -> Result<Term, Term> {
let _ = ctx;
args.first().copied().ok_or(Term::NIL)
}
#[test]
fn descriptor_exposes_identity_dirty_flag_and_determinism() {
let nif = Nif::pure("example/module", "identity", 1, identity_native);
assert_eq!(nif.module(), "example/module");
assert_eq!(nif.function(), "identity");
assert_eq!(nif.arity(), 1);
assert!(!nif.is_dirty());
assert_eq!(nif.determinism(), Determinism::Pure);
assert_eq!(nif.native() as usize, identity_native as usize);
}
}