### NIF Registration Example Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/nif_basics.md An example demonstrating the `rustler::init!` macro with three NIF functions: `add`, `multiply`, and `greet`. All listed functions must have the `#[rustler::nif]` attribute. ```rust #[rustler::nif] fn add(a: i32, b: i32) -> i32 { a + b } #[rustler::nif] fn multiply(a: i32, b: i32) -> i32 { a * b } #[rustler::nif] fn greet(env: Env, name: String) -> Term { format!("Hello, {}", name).encode(env) } rustler::init!("Elixir.Math", [add, multiply, greet]); ``` -------------------------------- ### Minimal NIF Example Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/quick_reference.md Demonstrates the simplest form of a NIF function and its registration with Rustler. ```rust #[rustler::nif] fn add(a: i32, b: i32) -> i32 { a + b } ustler::init!("Elixir.Math", [add]); ``` -------------------------------- ### Working with Binary Data Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/quick_reference.md Examples for creating binary data from byte vectors, creating owned binaries for modification, and decoding binary terms. ```rust // Create from vec let bytes = vec![1, 2, 3, 4, 5]; let binary = bytes.encode(env); // Create owned let mut owned = OwnedBinary::new(100)?; owned.as_mut_slice()[0] = 42; let immutable = owned.release(env); // Decode let binary: Binary = term.decode()?; let bytes: Vec = binary.as_slice().to_vec(); ``` -------------------------------- ### Minimal NIF Example: Add Two Numbers Source: https://github.com/rusterlium/rustler/blob/master/README.md This is a basic example of a Rust NIF that adds two 64-bit integers and returns the result. It requires the `rustler::nif` attribute and `rustler::init` to define the module. ```rust #[rustler::nif] fn add(a: i64, b: i64) -> i64 { a + b } rustler::init!("Elixir.Math"); ``` -------------------------------- ### Term Comparison Example Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/term.md Demonstrates that two encoded terms representing the same value are equal. This relies on the `PartialEq` implementation for `Term`. ```rust let term1 = 42i32.encode(env); let term2 = 42i32.encode(env); assert_eq!(term1, term2); ``` -------------------------------- ### Binary Operations Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/types.md Example of performing bitwise operations on binary data. ```APIDOC ## Binary Operations ```rust #[rustler::nif] fn xor_binary(env: Env, input: Binary) -> NifResult { let mut output = OwnedBinary::new(input.len()) .ok_or(Error::Term(Box::new("allocation failed"))) ?; for (i, &byte) in input.as_slice().iter().enumerate() { output.as_mut_slice()[i] = byte ^ 0xAA; } Ok(output.release(env).encode(env)) } ``` ``` -------------------------------- ### Encoding Rust to Erlang Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/types.md Example of encoding Rust data structures into Erlang terms. ```APIDOC ## Encoding Rust to Erlang ```rust #[rustler::nif] fn build_response(env: Env) -> Term { // Encode tuple let result = ("ok", 42, vec!["a", "b"]); result.encode(env) // Equivalent to: {:ok, 42, ["a", "b"]} } ``` ``` -------------------------------- ### Optional Arguments with Option Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/nif_basics.md Demonstrates using `Option` for optional NIF arguments. The example shows how to provide a default value using `unwrap_or`. ```rust #[rustler::nif] fn fetch(url: String, timeout: Option) -> NifResult { let timeout = timeout.unwrap_or(30); // Use timeout... Ok(String::new()) } ``` ```elixir MyNif.fetch("http://example.com") # timeout = None MyNif.fetch("http://example.com", 60) # timeout = Some(60) ``` -------------------------------- ### Resource `down` Callback Implementation and NIF for Monitoring Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/resources.md Example implementation of the `down` callback for a `Resource` and a NIF function that uses `ResourceArc::monitor` to monitor a process. ```rust #[rustler::resource_impl] impl Resource for MyData { fn down(&self, env: Env, pid: LocalPid, monitor: Monitor) { eprintln!("Process {:?} died", pid); } } #[rustler::nif] fn monitor_process(env: Env, resource: ResourceArc, pid: LocalPid) -> Atom { resource.monitor(Some(env), &pid); atom::ok() } ``` -------------------------------- ### Decoding Erlang to Rust Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/types.md Example of decoding Erlang terms into Rust types, with error handling. ```APIDOC ## Decoding Erlang to Rust ```rust #[rustler::nif] fn process_args(env: Env, arg: Term) -> NifResult { // Try multiple decoders if let Ok(num) = arg.decode::() { Ok(num) } else if let Ok(s) = arg.decode::() { Ok(s.len() as i32) } else { Err(Error::BadArg) } } ``` ``` -------------------------------- ### Tuple Methods Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/data_structures.md Core methods for interacting with tuples, such as getting their size and retrieving specific elements. ```APIDOC ## Tuple Methods ### `tuple_size(self) -> NifResult` ### Description Returns tuple size. ### Example ```rust let size = my_tuple.tuple_size()?; ``` ### `tuple_get(self, index: usize) -> NifResult>` ### Description Gets element at index (0-based). ### Example ```rust let first = tuple.tuple_get(0)?; let second = tuple.tuple_get(1)?; ``` ### `tuple_from_array(env: Env<'a>, elements: &[impl Encoder]) -> Term<'a>` ### Description Creates tuple from array. ``` -------------------------------- ### Binary Methods Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/data_structures.md Core methods for inspecting binary data, such as getting its slice representation, length, and checking if it's empty. ```APIDOC ## Binary Methods ### `as_slice(&self) -> &[u8]` ### Description Returns immutable data. ### `len(&self) -> usize` ### Description Returns binary size. ### `is_empty(&self) -> bool` ### Description Returns true if size is 0. ### `to_owned(&self) -> Option` ### Description Copies to owned binary. ``` -------------------------------- ### Minimal NIF Example Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/nif_basics.md A basic NIF function that takes two integers and returns their sum. This is the simplest form of a NIF. ```rust #[rustler::nif] fn add(a: i32, b: i32) -> i32 { a + b } ``` -------------------------------- ### Spawning Async Computation with ThreadSpawner Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/threading_scheduling.md Example of spawning a background thread to perform an expensive computation using `ThreadSpawner`. The result is sent back to the calling process asynchronously. ```rust use rustler::thread::{JobSpawner, ThreadSpawner}; #[rustler::nif] fn async_computation(env: Env, n: i64) -> Atom { let pid = env.pid(); ThreadSpawner::spawn(move || { // This runs on separate thread let result = expensive_work(n); // Send result back to process let mut msg_env = OwnedEnv::new(); let _ = msg_env.send_and_clear(&pid, |e| { ("result", result).encode(e) }); }); atom::ok() } ``` -------------------------------- ### Working with Maps in NIF Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/term.md Demonstrates how to interact with map terms within a Rustler NIF. It shows how to get the size of a map, retrieve a value by key, and add a new key-value pair to create a new map. ```rust #[rustler::nif] fn process_map(env: Env, map_term: Term) -> NifResult { let map_size = map_term.map_size()?; let value_for_key = map_term.map_get("my_key")?; let new_map = map_term.map_put("new_key", "new_value")?; Ok(new_map) } ``` -------------------------------- ### Storing a Resource Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/quick_reference.md Example of a NIF function that creates and returns a `ResourceArc`, making a Rust struct available in Elixir. ```rust #[rustler::nif] fn create_resource(value: i32) -> ResourceArc { ResourceArc::new(MyData { value }) } ``` -------------------------------- ### Manual Tuple Encoder Implementation Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/types.md Example of manually implementing the Encoder trait for a tuple type (i32, String). This demonstrates how to handle custom tuple encoding by delegating to existing implementations. ```rust impl Encoder for (i32, String) { fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { (self.0, self.1.clone()).encode(env) } } ``` -------------------------------- ### NIF Validating Input with NifResult Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/nif_basics.md Example of a NIF using `NifResult` to validate input. It returns `Ok` with a doubled value if positive, or an `Err` atom otherwise. ```rust #[rustler::nif] fn validate(value: i32) -> NifResult { if value > 0 { Ok(value * 2) } else { Err(Error::Atom("must_be_positive")) } } ``` -------------------------------- ### Get Binary Length Method Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/data_structures.md A method to get the size of a binary in bytes. ```rust input.len() ``` -------------------------------- ### Get Tuple Size Method Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/data_structures.md A method to get the size of a tuple. Assumes the `Term` is a valid tuple. ```rust let size = my_tuple.tuple_size()?; ``` -------------------------------- ### Basic Resource Creation and Usage Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/resources.md Illustrates the fundamental pattern for creating a resource, implementing the `Resource` trait, and exposing functions to open and read from it. ```rust use rustler::{ResourceArc, Resource, Env, Term}; pub struct FileHandle { name: String, data: Vec, } #[rustler::resource_impl] impl Resource for FileHandle {} #[rustler::nif]fn open_file(env: Env, name: String) -> Term { let handle = ResourceArc::new(FileHandle { name: name.clone(), data: Vec::new(), }); handle.encode(env) } #[rustler::nif]fn read_file(resource: ResourceArc) -> String { format!("File: {}", resource.name) } ``` -------------------------------- ### Creating a Binary from Resource Data Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/resources.md Shows how to create an Erlang binary from a resource's data using the `make_binary` method. ```rust pub struct Buffer { data: Vec, } #[rustler::resource_impl] impl Resource for Buffer {} #[rustler::nif]fn get_buffer_binary(env: Env, resource: ResourceArc) -> Term { let binary = resource.make_binary(env, |buf| &buf.data); binary.encode(env) } ``` -------------------------------- ### Monitoring a Process with a Resource Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/quick_reference.md Demonstrates how to initiate a monitor on an Elixir process from a NIF and handle process termination notifications. ```rust #[rustler::nif] fn monitor(env: Env, resource: ResourceArc, pid: LocalPid) -> Atom { resource.monitor(Some(env), &pid); atom::ok() } // In resource definition: impl Resource for MyData { const IMPLEMENTS_DOWN: bool = true; fn down(&self, _env: Env, pid: LocalPid, _monitor: Monitor) { println!("Process {:?} terminated", pid); } } ``` -------------------------------- ### Get Associated Environment Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/term.md Retrieve the `Env<'a>` that a `Term` belongs to. ```rust let env = my_term.get_env(); ``` -------------------------------- ### Get Binary Size Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/types.md Returns the size of the binary data in bytes. ```rust pub fn len(&self) -> usize ``` -------------------------------- ### Working with Options Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/types.md Demonstrates handling optional arguments using Rustler's decoding capabilities. ```APIDOC ## Working with Options ```rust #[rustler::nif] fn optional_arg(env: Env, maybe_value: Term) -> Term { let opt: Option = maybe_value.decode().unwrap_or(None); match opt { Some(x) => format!("Got {}", x).encode(env), None => "no value".encode(env), } } ``` ``` -------------------------------- ### Resource with Process Monitoring Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/resources.md Demonstrates how to implement process monitoring for a resource. The `down` callback is invoked when the monitored process terminates. ```rust pub struct Connection { pid: LocalPid, } #[rustler::resource_impl] impl Resource for Connection { const IMPLEMENTS_DOWN: bool = true; fn down(&self, _env: Env, _pid: LocalPid, _monitor: Monitor) { eprintln!("Connection lost!"); } } #[rustler::nif]fn connect(env: Env, remote_pid: LocalPid) -> Term { let conn = ResourceArc::new(Connection { pid: remote_pid }); conn.monitor(Some(env), &remote_pid); conn.encode(env) } ``` -------------------------------- ### Custom Job Spawner Implementation Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/threading_scheduling.md Implement the `JobSpawner` trait to create custom thread pooling or job distribution mechanisms. This example shows a basic structure using a channel for sending jobs to a thread pool. ```rust use rustler::thread::JobSpawner; use std::sync::mpsc; pub struct ChannelSpawner { tx: mpsc::Sender>, } impl JobSpawner for ChannelSpawner { fn spawn(job: F) { // Send job to thread pool via channel // Requires maintaining global channel } } ``` -------------------------------- ### Get Binary Length Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/data_structures.md Returns the number of bytes in a binary reference. This is a read-only operation. ```rust #[rustler::nif] fn process_binary(input: Binary) -> usize { input.len() } ``` -------------------------------- ### Get Binary Data Slice Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/types.md Returns an immutable slice view of the binary data. ```rust pub fn as_slice(&self) -> &[u8] ``` -------------------------------- ### Export NIFs with on_load function using rustler::init! (New) Source: https://github.com/rusterlium/rustler/blob/master/UPGRADE.md Demonstrates how to specify an `on_load` function when initializing NIFs with the new `rustler::init!` macro. ```rust rustler::init!("Elixir.Math", [add, long_running_operation], load = a_function); ``` -------------------------------- ### Binary Module Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/module_reference.md Documentation for `Binary`, `OwnedBinary`, and `NewBinary` types, covering methods for creating, manipulating, and accessing binary data. ```APIDOC ## Module: rustler::types::binary Binary data (byte sequences). ### Types: #### `Binary<'a>` Immutable binary reference. Tied to environment lifetime. **Key Methods:** - `from_term(term: Term<'a>) -> NifResult` - `from_iolist(term: Term<'a>) -> NifResult` - `from_owned(owned: OwnedBinary, env: Env<'a>) -> Binary<'a>` - `as_slice(&self) -> &[u8]` - `len(&self) -> usize` - `is_empty(&self) -> bool` - `to_owned(&self) -> Option` #### `OwnedBinary` Mutable owned binary. **Key Methods:** - `new(size: usize) -> Option` - `from_unowned(src: &Binary) -> Option` - `realloc(&mut self, size: usize) -> bool` - `realloc_or_copy(&mut self, size: usize)` - `as_slice(&self) -> &[u8]` - `as_mut_slice(&mut self) -> &mut [u8]` - `release(self, env: Env) -> Binary` #### `NewBinary<'a>` Specialized binary for small allocations. **Key Methods:** - `new(env: Env<'a>, size: usize) -> NifResult>` - `as_mut_slice(&mut self) -> &mut [u8]` ``` -------------------------------- ### Create New Small Binary Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/types.md Creates a new small binary on the environment's heap with the specified size. Returns an error if allocation fails. ```rust pub fn new(env: Env<'a>, size: usize) -> NifResult> ``` -------------------------------- ### NIF with Environment Parameter Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/nif_basics.md Demonstrates a NIF that accepts an `Env` parameter, which is necessary for encoding terms. The `Env` must be the first parameter. ```rust #[rustler::nif] fn process(env: Env, value: i32) -> Term { format!("Received: {}", value).encode(env) } ``` -------------------------------- ### Get Binary Slice Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/data_structures.md Provides an immutable slice view of the binary data. This is a zero-copy operation. ```rust input.as_slice() ``` -------------------------------- ### NIF Scheduling Options Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/nif_basics.md Shows how to specify the scheduler context for a NIF using the `schedule` attribute parameter. Options include `Normal`, `DirtyCpu`, and `DirtyIo`. ```rust #[rustler::nif(schedule = "Normal")] fn lightweight_task() -> i32 { /* */ } #[rustler::nif(schedule = "DirtyCpu")] fn cpu_intensive() -> i32 { /* */ } #[rustler::nif(schedule = "DirtyIo")] fn io_operation() -> Vec { /* */ } ``` -------------------------------- ### Get Mutable Slice of NewBinary Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/types.md Returns a mutable slice view of the NewBinary's data. ```rust pub fn as_mut_slice(&mut self) -> &mut [u8] ``` -------------------------------- ### NewBinary Methods Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/types.md Methods for creating and managing small binary allocations. ```APIDOC ## `new(env: Env<'a>, size: usize) -> NifResult>` Creates new small binary in environment heap. ## `as_mut_slice(&mut self) -> &mut [u8]` Returns mutable data slice. ``` -------------------------------- ### Get Tuple Size Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/data_structures.md Retrieves the number of elements in an Erlang tuple. Returns an error if the term is not a tuple. ```rust #[rustler::nif] fn tuple_size(tuple: Term) -> NifResult { tuple.tuple_size() } ``` -------------------------------- ### Working with Elixir Lists Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/quick_reference.md Demonstrates creating, decoding, iterating, and accessing elements of Elixir lists within Rust. ```rust // Create let list = vec![1, 2, 3].encode(env); let empty = Term::list_new_empty(env); // Decode to Vec let numbers: Vec = list_term.decode()?; // Iterate let iter: ListIterator = list_term.decode()?; for item in iter { let value: i32 = item.decode()?; } // Access let length = list_term.list_length()?; let (head, tail) = list_term.list_get_cell()?; ``` -------------------------------- ### Accepting a Resource in a NIF Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/resources.md Demonstrates how a NIF can accept a resource as an argument. Resources are automatically encoded/decoded by Rustler. ```rust #[rustler::nif] fn accept_resource(resource: ResourceArc) -> Atom { atom::ok() } ``` -------------------------------- ### Get Map Value by Key Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/data_structures.md Retrieves the value associated with a given key from a map. The key must be encodable. ```rust #[rustler::nif] fn read_config(map: Term, key: String) -> NifResult { map.map_get(key) } ``` -------------------------------- ### Run NIF Record Benchmark Source: https://github.com/rusterlium/rustler/blob/master/rustler_benchmarks/README.md Execute the NIF record benchmark using `mix run`. This command compiles the benchmark in release mode and runs the specified module, showing performance metrics for decode and encode operations. ```bash $ mix run -e Benchmark.NifRecord.run Name ips average deviation median 99th % decode 1.20 M 0.83 μs ±689.21% 0.49 μs 2.22 μs decode and encode 0.80 M 1.25 μs ±1472.17% 0.65 μs 3.51 μs Comparison: decode 1.20 M decode and encode 0.80 M - 1.50x slower +0.42 μs ``` -------------------------------- ### Get Term Size Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/term.md Determine the memory size of a term in bytes using the `size` method. This requires the `nif_version_2_18` feature. ```rust let term_size = my_term.size(); ``` -------------------------------- ### Working with Elixir Maps Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/quick_reference.md Shows how to create, decode, access, and modify Elixir maps using Rust. Utilizes the `term_map!` macro for creation. ```rust // Create let map = term_map!(env, { "key" => "value", "count" => 42, }); // Decode to HashMap let data: HashMap = map_term.decode()?; // Access let value = map_term.map_get("key")?; let size = map_term.map_size()?; // Modify let updated = map_term.map_put("new_key", 100)?; let removed = map_term.map_remove("key")?; ``` -------------------------------- ### Extract Raw NIF_TERM Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/term.md Use `as_c_arg` to get the raw term pointer for passing to Erlang NIF C functions. ```rust let raw = my_term.as_c_arg(); ``` -------------------------------- ### Create Binary from NewBinary Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/data_structures.md Creates a new binary of a specified size and copies content into it. Returns an error if the initial allocation fails. ```rust #[rustler::nif] fn new_binary(env: Env, content: String) -> NifResult { let mut binary = NewBinary::new(env, content.len())?; binary.as_mut_slice().copy_from_slice(content.as_bytes()); Ok(binary.encode(env)) } ``` -------------------------------- ### Export NIFs using rustler::init! (New) Source: https://github.com/rusterlium/rustler/blob/master/UPGRADE.md The new method for exporting NIFs, which is simpler and works in conjunction with the `rustler::nif` proc_macro. ```rust rustler::init!("Elixir.Math", [add, long_running_operation]); ``` -------------------------------- ### Run NIF Struct Benchmark Source: https://github.com/rusterlium/rustler/blob/master/rustler_benchmarks/README.md Execute the NIF struct benchmark using `mix run`. This command compiles the benchmark in release mode and runs the specified module. ```bash $ mix run -e Benchmark.NifStruct.run Name ips average deviation median 99th % decode 404.50 K 2.47 μs ±651.07% 1.63 μs 7.23 μs decode and encode 117.27 K 8.53 μs ±306.83% 6.34 μs 33.76 μs Comparison: decode 404.50 K decode and encode 117.27 K - 3.45x slower +6.06 μs ``` -------------------------------- ### Get Erlang Term Type Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/term.md Retrieve the Erlang type of a term using `get_erl_type`. This method requires the `nif_version_2_15` feature to be enabled. ```rust let term_type = my_term.get_erl_type(); ``` -------------------------------- ### Get Tuple Element Method Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/data_structures.md A method to retrieve an element from a tuple by its index. Assumes the `Term` is a valid tuple and the index is within bounds. ```rust let first = tuple.tuple_get(0)?; let second = tuple.tuple_get(1)?; ``` -------------------------------- ### Using a Resource Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/quick_reference.md A NIF function demonstrating how to accept and access data from a `ResourceArc` passed from Elixir. ```rust #[rustler::nif] fn get_value(resource: ResourceArc) -> i32 { resource.value } ``` -------------------------------- ### Get C Argument from ResourceArc Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/module_reference.md Retrieves a raw C pointer to the resource data, suitable for passing to C functions. This is an unsafe operation. ```rust let c_ptr: *const c_void = resource_arc.as_c_arg(); ``` -------------------------------- ### Get Erlang List Length Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/data_structures.md Retrieves the number of elements in an Erlang list using the `list_length` method. Requires the input term to be a list. ```rust #[rustler::nif] fn get_length(list: Term) -> NifResult { list.list_length() } ``` -------------------------------- ### List Term Methods Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/term.md Methods for working with lists, including creating empty lists, iterating, getting length, accessing elements, and reversing. ```APIDOC ## list_new_empty env: Env<'a>) -> Term<'a> ### Description Returns a new empty list `[]`. ### Method POST ### Endpoint /list_new_empty ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```json { "env": "Env<'a>" } ``` ### Response #### Success Response (200) - **Term<'a>** - The newly created empty list. #### Response Example ```json { "term": "[]" } ``` ``` ```APIDOC ## into_list_iterator(self) -> NifResult> ### Description Returns an iterator over list elements. ### Method POST ### Endpoint /into_list_iterator ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```json { "self": "Term<'a>" } ``` ### Response #### Success Response (200) - **ListIterator<'a>** - An iterator over the list elements. #### Response Example ```json { "iterator": "ListIterator<'a>" } ``` ### Error Handling **Throws:** `Error::BadArg` if the term is not a list. ``` ```APIDOC ## list_length(self) -> NifResult ### Description Returns the length of the list. ### Method POST ### Endpoint /list_length ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```json { "self": "Term<'a>" } ``` ### Response #### Success Response (200) - **usize** - The number of elements in the list. #### Response Example ```json { "length": 5 } ``` ### Error Handling **Throws:** `Error::BadArg` if the term is not a list. ``` ```APIDOC ## list_get_cell(self) -> NifResult<(Term<'a>, Term<'a>) ### Description Unpacks a list into its head and tail. ### Method POST ### Endpoint /list_get_cell ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```json { "self": "Term<'a>" } ``` ### Response #### Success Response (200) - **(Term<'a>, Term<'a>)** - A tuple containing the head and tail of the list. #### Response Example ```json { "head": "Term<'a>", "tail": "Term<'a>" } ``` ### Error Handling **Throws:** `Error::BadArg` if the term is not a list. ``` ```APIDOC ## list_reverse(self) -> NifResult> ### Description Returns a reversed copy of the list. ### Method POST ### Endpoint /list_reverse ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```json { "self": "Term<'a>" } ``` ### Response #### Success Response (200) - **Term<'a>** - A new term representing the reversed list. #### Response Example ```json { "reversed_list": "Term<'a>" } ``` ### Error Handling **Throws:** `Error::BadArg` if the term is not a list. ``` -------------------------------- ### Generate New Rustler Project Source: https://github.com/rusterlium/rustler/blob/master/rustler_mix/README.md Use the `mix rustler.new` task to generate the boilerplate for a new Rustler project. Follow the on-screen instructions for project configuration. ```bash $ mix rustler.new ``` -------------------------------- ### Get Raw C Pid Argument Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/types.md Returns the raw C representation of the Erlang PID, suitable for use in NIF C functions. ```rust pub fn as_c_arg(&self) -> ErlNifPid ``` -------------------------------- ### NIF with Environment Interaction Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/quick_reference.md Shows how to use the `Env` to encode a Rust string into an Elixir `Term`. ```rust #[rustler::nif] fn process(env: Env, value: i32) -> Term { format!("Got: {}", value).encode(env) } ``` -------------------------------- ### Binary Creation Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/data_structures.md Methods for creating binary data structures from various sources like owned buffers, new allocations, and slices. ```APIDOC ## Creating Binary ### From OwnedBinary ```rust #[rustler::nif] fn create_binary(env: Env) -> NifResult { let mut bin = OwnedBinary::new(5) .ok_or(Error::Atom("allocation_failed"))?; bin.as_mut_slice().copy_from_slice(b"hello"); Ok(Binary::from_owned(bin, env).encode(env)) } ``` ### From NewBinary ```rust #[rustler::nif] fn new_binary(env: Env, content: String) -> NifResult { let mut binary = NewBinary::new(env, content.len())?; binary.as_mut_slice().copy_from_slice(content.as_bytes()); Ok(binary.encode(env)) } ``` ### From Slice ```rust #[rustler::nif] fn bytes_to_binary(env: Env, bytes: Vec) -> Term { bytes.encode(env) } ``` ``` -------------------------------- ### Create a new OwnedEnv Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/environment.md Allocates a new process-independent environment. This is the first step before sending messages or running closures in a background thread. ```rust let mut msg_env = OwnedEnv::new(); ``` -------------------------------- ### Performance: Use Dirty Schedulers (CPU and I/O) Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/nif_basics.md Shows how to offload work to separate scheduler threads using `DirtyCpu` for CPU-bound tasks and `DirtyIo` for I/O-bound tasks, preventing blocking of the main Erlang scheduler. ```rust // For CPU work #[rustler::nif(schedule = "DirtyCpu")] fn fibonacci(n: u32) -> u64 { // Don't block scheduler thread } // For I/O work #[rustler::nif(schedule = "DirtyIo")] fn read_file(path: String) -> NifResult> { std::fs::read(path).map_err(|_| Error::Atom("read_failed")) } ``` -------------------------------- ### Map Term Methods Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/term.md Methods for working with maps, including creating empty maps, creating from arrays/pairs, getting values, size, and modifying maps. ```APIDOC ## map_new(env: Env<'a>) -> Term<'a> ### Description Returns a new empty map `{}`. ### Method POST ### Endpoint /map_new ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```json { "env": "Env<'a>" } ``` ### Response #### Success Response (200) - **Term<'a>** - The newly created empty map. #### Response Example ```json { "map": "{}" } ``` ``` ```APIDOC ## map_from_arrays(env: Env<'a>, keys: &[impl Encoder], values: &[impl Encoder]) -> NifResult> ### Description Creates a map from parallel key and value arrays. ### Method POST ### Endpoint /map_from_arrays ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **keys** (array of Encoder) - The keys for the map. - **values** (array of Encoder) - The values for the map. ### Request Example ```json { "env": "Env<'a>", "keys": ["key1", "key2"], "values": ["value1", "value2"] } ``` ### Response #### Success Response (200) - **Term<'a>** - The newly created map. #### Response Example ```json { "map": "{key1: value1, key2: value2}" } ``` ``` ```APIDOC ## map_from_term_arrays(env: Env<'a>, keys: &[Term<'a>], values: &[Term<'a>]) -> NifResult> ### Description Creates a map from already-encoded term arrays. ### Method POST ### Endpoint /map_from_term_arrays ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **keys** (array of Term<'a>) - The keys for the map. - **values** (array of Term<'a>) - The values for the map. ### Request Example ```json { "env": "Env<'a>", "keys": ["term_key1", "term_key2"], "values": ["term_value1", "term_value2"] } ``` ### Response #### Success Response (200) - **Term<'a>** - The newly created map. #### Response Example ```json { "map": "{term_key1: term_value1, term_key2: term_value2}" } ``` ``` ```APIDOC ## map_from_pairs(env: Env<'a>, pairs: &[(impl Encoder, impl Encoder)]) -> NifResult> ### Description Creates a map from (key, value) pairs. ### Method POST ### Endpoint /map_from_pairs ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **pairs** (array of tuples) - An array of (key, value) pairs. ### Request Example ```json { "env": "Env<'a>", "pairs": [["key1", "value1"], ["key2", "value2"]] } ``` ### Response #### Success Response (200) - **Term<'a>** - The newly created map. #### Response Example ```json { "map": "{key1: value1, key2: value2}" } ``` ``` ```APIDOC ## map_get(self, key: impl Encoder) -> NifResult> ### Description Gets the value associated with a key in the map. ### Method POST ### Endpoint /map_get ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **key** (Encoder) - The key to look up. ### Request Example ```json { "self": "Term<'a>", "key": "my_key" } ``` ### Response #### Success Response (200) - **Term<'a>** - The value associated with the key. #### Response Example ```json { "value": "my_value" } ``` ### Error Handling **Throws:** `Error::BadArg` if the term is not a map or the key is missing. ``` ```APIDOC ## map_size(self) -> NifResult ### Description Returns the number of entries in the map. ### Method POST ### Endpoint /map_size ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```json { "self": "Term<'a>" } ``` ### Response #### Success Response (200) - **usize** - The number of entries in the map. #### Response Example ```json { "size": 10 } ``` ### Error Handling **Throws:** `Error::BadArg` if the term is not a map. ``` ```APIDOC ## map_put(self, key: impl Encoder, value: impl Encoder) -> NifResult> ### Description Returns a copy of the map with the key set to the specified value. ### Method POST ### Endpoint /map_put ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **key** (Encoder) - The key to set. - **value** (Encoder) - The value to associate with the key. ### Request Example ```json { "self": "Term<'a>", "key": "new_key", "value": "new_value" } ``` ### Response #### Success Response (200) - **Term<'a>** - A new term representing the map with the updated key-value pair. #### Response Example ```json { "updated_map": "{...}" } ``` ### Error Handling **Throws:** `Error::BadArg` if the term is not a map. ``` ```APIDOC ## map_remove(self, key: impl Encoder) -> NifResult> ### Description Returns a copy of the map with the specified key removed. ### Method POST ### Endpoint /map_remove ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **key** (Encoder) - The key to remove. ### Request Example ```json { "self": "Term<'a>", "key": "key_to_remove" } ``` ### Response #### Success Response (200) - **Term<'a>** - A new term representing the map with the key removed. #### Response Example ```json { "updated_map": "{...}" } ``` ### Error Handling **Throws:** `Error::BadArg` if the term is not a map. ``` ```APIDOC ## map_update(self, key: impl Encoder, new_value: impl Encoder) -> NifResult> ### Description Returns a copy of the map with an existing key's value updated. ### Method POST ### Endpoint /map_update ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **key** (Encoder) - The key whose value needs to be updated. - **new_value** (Encoder) - The new value for the key. ### Request Example ```json { "self": "Term<'a>", "key": "existing_key", "new_value": "updated_value" } ``` ### Response #### Success Response (200) - **Term<'a>** - A new term representing the map with the updated value. #### Response Example ```json { "updated_map": "{...}" } ``` ### Error Handling **Throws:** `Error::BadArg` if the term is not a map or the key is missing. ``` -------------------------------- ### Check Binary Allocation Result Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/data_structures.md Shows the correct way to allocate a binary by checking the result of `OwnedBinary::new`. It uses `ok_or` to convert the `Option` to a `Result` and handle potential allocation failures gracefully. ```rust // Wrong: No error handling let bin = OwnedBinary::new(1_000_000_000).unwrap(); // Panics on failure // Right: Check allocation result let bin = OwnedBinary::new(1_000_000_000) .ok_or(Error::Atom("allocation_failed"))?; ``` -------------------------------- ### Spawning a Background Thread Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/quick_reference.md Shows how to use `ThreadSpawner` to run a potentially long-running computation in a background thread and send the result back to Elixir. ```rust use rustler::thread::ThreadSpawner; #[rustler::nif] fn async_work(env: Env, n: i64) -> Atom { let pid = env.pid(); ThreadSpawner::spawn(move || { let result = expensive_computation(n); let mut msg_env = OwnedEnv::new(); let _ = msg_env.send_and_clear(&pid, |e| { ("result", result).encode(e) }); }); atom::ok() } ``` -------------------------------- ### Logic Error Handling with NifResult Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/nif_basics.md Handles application-specific logic errors by returning `NifResult` with an appropriate error atom. This example validates an email format. ```rust #[rustler::nif] fn validate_email(email: String) -> NifResult { if email.contains('@') { Ok(atom::ok()) } else { Err(Error::Atom("invalid_email")) } } ``` -------------------------------- ### NIF Processing ResourceArc Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/nif_basics.md Example of a NIF that takes a `ResourceArc`, which is a handle to a resource managed by Rustler. This allows interacting with Rust data structures from Erlang. ```rust #[rustler::nif] fn process_file(file: ResourceArc) -> String { file.name.clone() } ``` -------------------------------- ### OwnedEnv::new Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/environment.md Allocates a new process-independent environment for building Erlang terms. ```APIDOC ## OwnedEnv::new ### Description Allocates a new process-independent environment. ### Returns `OwnedEnv` — New environment ### Example ```rust let mut msg_env = OwnedEnv::new(); msg_env.send_and_clear(&pid, |env| "hello".encode(env))?; ``` ``` -------------------------------- ### Get Tuple Element by Index Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/data_structures.md Retrieves a specific element from an Erlang tuple using its 0-based index. Returns an error if the index is out of bounds or the term is not a tuple. ```rust #[rustler::nif] fn tuple_element(tuple: Term, index: usize) -> NifResult { tuple.tuple_get(index) } ``` -------------------------------- ### Create Binary from OwnedBinary Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/data_structures.md Allocates a new binary with a specified size, copies data into it, and then converts it to an encodable `Binary` term. Handles potential allocation failures. ```rust #[rustler::nif] fn create_binary(env: Env) -> NifResult { let mut bin = OwnedBinary::new(5) .ok_or(Error::Atom("allocation_failed"))?; bin.as_mut_slice().copy_from_slice(b"hello"); Ok(Binary::from_owned(bin, env).encode(env)) } ``` -------------------------------- ### Represent Term in Different Environment Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/term.md Use `in_env` to get a representation of the term in a different environment. A copy may be made if the term is not already in the target environment. ```rust let term1: Term = /* in env1 */; let term2 = term1.in_env(env2); // Copies if needed ``` -------------------------------- ### Asynchronous Computation with Background Threads Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/README.md Demonstrates running computationally intensive tasks in a background thread without blocking the Erlang VM. Use this for long-running operations to maintain responsiveness. ```rust use rustler::thread::ThreadSpawner; #[rustler::nif] fn compute_async(env: Env, n: i64) -> Atom { let pid = env.pid(); ThreadSpawner::spawn(move || { let result = expensive_work(n); // Assuming expensive_work is defined elsewhere let mut msg_env = OwnedEnv::new(); let _ = msg_env.send_and_clear(&pid, |e| { ("result", result).encode(e) }); }); atom::ok() } ``` -------------------------------- ### Map and List Operations in Rustler Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/README.md Shows how to build, access maps, and iterate over lists in Rustler. Ensure proper decoding of list items. ```rust // Build map let map = term_map!(env, { "key1" => value1, "key2" => value2, }); // Access map let val = map.map_get("key1")?; // Iterate list let iter: ListIterator = list_term.decode()?; for item in iter { let val: T = item.decode()?; } ``` -------------------------------- ### NIF with Vec Parameter Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/nif_basics.md Example of a NIF that accepts a `Vec`, which is decoded from an Erlang list of integers. The function calculates the sum of the list elements. ```rust #[rustler::nif] fn sum_list(values: Vec) -> i32 { values.iter().sum() } ``` -------------------------------- ### Encoding Rust Types to Terms Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/quick_reference.md Examples of encoding Rust data types into Elixir `Term`s using the `encode` method. Requires the `Encoder` trait and an `Env`. ```rust let int_term = 42i32.encode(env); let string_term = "hello".encode(env); let vec_term = vec![1, 2, 3].encode(env); let tuple_term = (1, "two", 3.0).encode(env); let custom_term = my_struct.encode(env); ``` -------------------------------- ### Debugging: Printing Values to Stdout Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/nif_basics.md Shows how to print debug information from a NIF to standard output using `println!`. This is useful for inspecting the values of terms during development. ```rust #[rustler::nif] fn debug_value(env: Env, term: Term) -> Atom { println!("Debug: {:?}", term); // Prints to stdout atom::ok() } ``` -------------------------------- ### Get First Element of Erlang List Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/data_structures.md Extracts the head (first element) of an Erlang list using `list_get_cell`. Returns an error if the term is not a list or is an empty list. ```rust #[rustler::nif] fn first_element(env: Env, list: Term) -> NifResult { let (head, _tail) = list.list_get_cell()?; Ok(head) } ``` -------------------------------- ### Composing Attributes for Complex Structs Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/macros_and_attributes.md Attributes can be combined to define complex data structures. For example, a struct can contain nested structs or vectors, which are automatically encoded appropriately. ```rust #[derive(NifStruct)] #[module = "Elixir.User"] pub struct User { pub name: String, pub roles: Vec, // Vector auto-encoded as list pub metadata: MyMap, // Nested struct } #[derive(NifMap)] pub struct MyMap { pub created_at: String, pub updated_at: String, } ``` -------------------------------- ### Decoding Terms to Rust Types Source: https://github.com/rusterlium/rustler/blob/master/_autodocs/quick_reference.md Examples of decoding various Elixir `Term` types into corresponding Rust types using the `decode` method. Requires the `Decoder` trait. ```rust let int_val: i32 = term.decode()?; let string_val: String = term.decode()?; let list_val: Vec = term.decode()?; let map_val: HashMap = term.decode()?; let custom: MyStruct = term.decode()?; ```