mod erlang_stubs;
use crate::atom::{Atom, AtomTable};
use crate::native::{
BifRegistryImpl, Capability, NativeFn, NativeRegistrationError, ProcessContext,
};
use crate::term::Term;
use erlang_stubs::{
bif_code_priv_dir, bif_connect_node, bif_ensure_all_started, bif_os_getenv_0, bif_os_getenv_1,
bif_os_putenv, bif_os_type, bif_os_unsetenv, bif_string_split,
};
type OtpBif = (&'static str, &'static str, u8, Capability, NativeFn);
const OTP_STUBS: &[OtpBif] = &[
(
"gleam_otp_external",
"application_stopped",
0,
Capability::Pure,
bif_application_stopped,
),
(
"supervisor",
"start_link",
2,
Capability::Pure,
bif_supervisor_start_link,
),
(
"application",
"ensure_all_started",
1,
Capability::Pure,
bif_ensure_all_started,
),
("os", "getenv", 0, Capability::ExternalIo, bif_os_getenv_0),
("os", "getenv", 1, Capability::ExternalIo, bif_os_getenv_1),
("os", "putenv", 2, Capability::ExternalIo, bif_os_putenv),
("os", "unsetenv", 1, Capability::ExternalIo, bif_os_unsetenv),
("os", "type", 0, Capability::ExternalIo, bif_os_type),
(
"code",
"priv_dir",
1,
Capability::ExternalIo,
bif_code_priv_dir,
),
(
"net_kernel",
"connect_node",
1,
Capability::ExternalIo,
bif_connect_node,
),
("string", "split", 2, Capability::Pure, bif_string_split),
];
pub fn register_otp_stubs(
registry: &BifRegistryImpl,
atom_table: &AtomTable,
) -> Result<(), NativeRegistrationError> {
for &(module_name, function_name, arity, capability, native_function) in OTP_STUBS {
let module = atom_table.intern(module_name);
let function = atom_table.intern(function_name);
registry.register(module, function, arity, native_function, capability)?;
}
Ok(())
}
pub fn init_otp_atoms(atom_table: &AtomTable) {
erlang_stubs::init_erlang_atoms(atom_table);
}
pub fn bif_application_stopped(args: &[Term], _context: &mut ProcessContext) -> Result<Term, Term> {
if !args.is_empty() {
return Err(badarg());
}
Ok(Term::atom(Atom::OK))
}
pub fn bif_supervisor_start_link(
args: &[Term],
context: &mut ProcessContext,
) -> Result<Term, Term> {
let [_module, _init_args] = args else {
return Err(badarg());
};
let pid = context.pid().ok_or_else(badarg)?;
let pid_term = Term::try_pid(pid).ok_or_else(badarg)?;
context.alloc_tuple(&[Term::atom(Atom::OK), pid_term])
}
fn badarg() -> Term {
Term::atom(Atom::BADARG)
}
#[cfg(test)]
mod tests;