### Initialize Library with #[init] Attribute Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Shows how to use the `#[init]` attribute to register functions that run automatically when the BYOND library is first loaded. Useful for setup tasks like panic handlers and logging. ```rust use byondapi::prelude::*; #[byondapi::init] fn setup_library() { // Set up panic handler std::panic::set_hook(Box::new(|info| { let msg = format!("Rust panic: {:?}", info); std::fs::write("./rust_panic.log", msg).ok(); })); // Initialize logging env_logger::init(); // Pre-cache commonly used string IDs let _ = byond_string!("name"); let _ = byond_string!("health"); let _ = byond_string!("loc"); } ``` -------------------------------- ### Rust: Perform Map Operations with ByondXYZ Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Provides examples of working with BYOND map coordinates using `ByondXYZ`. Covers creating coordinates, locating turfs by coordinates, getting atom coordinates, and finding objects within a block or container. ```rust use byondapi::prelude::*; use byondapi::map::{ByondXYZ, byond_block, byond_locatexyz, byond_locatein, byond_xyz}; #[byondapi::bind] fn map_operations(atom: ByondValue) -> Result { // Create coordinates let coords = ByondXYZ::with_coords((10, 15, 1)); let (x, y, z) = coords.coordinates(); // Locate turf at coordinates let turf = byond_locatexyz(coords)?; // Get coordinates of an atom let atom_coords = byond_xyz(&atom)?; let (ax, ay, az) = atom_coords.coordinates(); // Get block of turfs between two corners let corner1 = ByondXYZ::with_coords((1, 1, 1)); let corner2 = ByondXYZ::with_coords((5, 5, 1)); let turfs: Vec = byond_block(corner1, corner2)?; println!("Found {} turfs in block", turfs.len()); // Locate object in container let type_to_find = ByondValue::try_from("/obj/item/weapon")?; let found = byond_locatein(&type_to_find, &atom)?; Ok(ByondValue::new_num(turfs.len() as f32)) } ``` -------------------------------- ### Rust: Create BYOND Objects with builtin_new Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Demonstrates instantiating new BYOND objects from Rust using `builtin_new` and `builtin_newarglist`. Covers creating objects from type paths and with constructor arguments or arglists. ```rust use byondapi::prelude::*; #[byondapi::bind] fn create_objects() -> Result { // Create object from type path string let type_path = ByondValue::try_from("/datum/myobject")?; let new_datum = ByondValue::builtin_new(type_path, &[])?; // Create with constructor arguments let mob_type = ByondValue::try_from("/mob/player")?; let new_mob = ByondValue::builtin_new(mob_type, &[ ByondValue::new_str("PlayerName")?, ByondValue::new_num(100.0), // starting health ])?; // Create with arglist (arguments from a list) let args_list = ByondValue::new_list()?; args_list.write_list(&[ ByondValue::new_str("arg1")?, ByondValue::new_num(42.0), ])?; let obj_type = ByondValue::try_from("/obj/item")?; let new_item = ByondValue::builtin_newarglist(obj_type, args_list)?; Ok(new_datum) } ``` -------------------------------- ### Rust: Create and Manipulate BYOND Lists Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Demonstrates creating, pushing, popping, reading, and writing elements to BYOND lists, including associative lists. Handles list length retrieval and conversion from Rust slices. ```rust use byondapi::prelude::*; #[byondapi::bind] fn list_operations(input_list: ByondValue) -> Result { // Create new list let mut new_list = ByondValue::new_list()?; // Push items new_list.push_list(ByondValue::new_num(1.0))?; new_list.push_list(ByondValue::new_str("item")?)?; // Pop last item if let Some(popped) = new_list.pop_list()? { println!("Popped: {:?}", popped.get_string()); } // Get list length let length: f32 = input_list.builtin_length()?.get_number()?; // Read by index (1-based in BYOND, but use f32) let first_item = input_list.read_list_index(1.0)?; // Write by index let mut list = input_list; list.write_list_index(2.0, ByondValue::new_num(42.0))?; // Associative list - read by key let value = list.read_list_index("my_key")?; list.write_list_index("my_key", "new_value")?; // Get all values (for assoc lists, gets values; for regular, gets items) let values: Vec = list.get_list_values()?; // Get key-value pairs as flat array [key1, val1, key2, val2, ...] let pairs: Vec = list.get_list()?; // Write entire list contents let items = vec![ ByondValue::new_num(1.0), ByondValue::new_num(2.0), ByondValue::new_num(3.0), ]; new_list.write_list(&items)?; // Convert slice to list let list_from_slice: ByondValue = items.as_slice().try_into()?; Ok(list_from_slice) } ``` -------------------------------- ### Create Simple Bound Function with #[bind] Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Use the #[bind] macro to create FFI-compatible functions callable from DM. Functions must return Result. ```rust use byondapi::prelude::*; // Simple function with no arguments - binds to /proc/test_connection #[byondapi::bind] fn test_connection() -> Result { Ok(ByondValue::new_num(42.0)) } ``` -------------------------------- ### Generate Bindings File Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Use #[test] and byondapi::generate_bindings to create the necessary DM binding stubs for your Rust functions. This is typically run during testing. ```rust use byondapi::prelude::*; // Generate bindings.dm file (run with cargo test) #[test] fn generate_binds() { byondapi::generate_bindings(env!("CARGO_CRATE_NAME")); } ``` -------------------------------- ### Create Bound Function with Arguments and Custom Path Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Bind a Rust function to a custom DM proc path using #[bind] and handle arguments. Ensure arguments are correctly converted and errors are propagated. ```rust use byondapi::prelude::*; // Function with arguments - binds to custom proc path #[byondapi::bind("/datum/myobject/proc/process_data")] fn process_data(src: ByondValue, multiplier: ByondValue) -> Result { let name = src.read_string("name")?; let mult: f32 = multiplier.try_into()?; let result = format!("{} x {}", name, mult); Ok(result.try_into()?) } ``` -------------------------------- ### Execute Code on BYOND Main Thread Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Illustrates using `thread_sync` to execute code on BYOND's main thread from a background thread. Supports both blocking and non-blocking synchronization. ```rust use byondapi::prelude::*; use byondapi::threadsync::thread_sync; use std::thread; #[byondapi::bind] fn async_operation() -> Result { // Spawn background thread for heavy computation thread::spawn(|| { // Do expensive work... let result = expensive_calculation(); // Sync back to BYOND's main thread (blocking) thread_sync(move || { // This runs on the main BYOND thread let result_val = ByondValue::new_num(result); byondapi::global_call::call_global("handle_result", &[result_val]) .unwrap_or_default() }, true); // true = block until complete // Non-blocking sync thread_sync(|| { ByondValue::new_str("Background task done").unwrap_or_default() }, false); // false = don't wait }); Ok(ByondValue::null()) } fn expensive_calculation() -> f32 { // Simulate heavy work 42.0 } ``` -------------------------------- ### Create Variable Argument Function with #[bind_raw_args] Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Use #[bind_raw_args] for functions accepting a variable number of arguments as a mutable slice. Remember to skip the first argument if it's the source object. ```rust use byondapi::prelude::*; #[byondapi::bind_raw_args("/proc/sum_all")] fn sum_all() -> Result { // args is &mut [ByondValue] containing src and all passed arguments let mut total: f32 = 0.0; // Skip first arg (src) and sum the rest for arg in args.iter().skip(1) { if arg.is_num() { total += arg.get_number()?; } } Ok(ByondValue::new_num(total)) } ``` -------------------------------- ### Rust: Iterate Over BYOND Lists Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Shows how to iterate over BYOND lists using Rust's iterator adapters. Supports iterating over key-value pairs, values only, and collecting string representations. ```rust use byondapi::prelude::*; #[byondapi::bind] fn process_list(list: ByondValue) -> Result { // Iterate over key-value pairs (value is null for non-assoc lists) for (key, value) in list.iter()? { if value.is_null() { // Non-associative item println!("Item: {:?}", key.get_string()); } else { // Associative pair println!("Key: {:?}, Value: {:?}", key.get_string(), value.get_number()); } } // Iterate over values only let doubled: Vec = list.values()? .filter_map(|v| v.get_number().ok()) .map(|n| ByondValue::new_num(n * 2.0)) .collect(); // Collect to Vec and process let strings: Vec = list.iter()? .filter_map(|(k, _)| k.get_string().ok()) .collect(); Ok(doubled.as_slice().try_into()?) } ``` -------------------------------- ### ByondValue Constructors Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Create ByondValue instances for null, numbers, strings, lists, and references using provided constructors. Type conversions are also supported. ```rust use byondapi::prelude::*; use byondapi::value::types::ValueType; // Create null value let null_val = ByondValue::null(); let default_val = ByondValue::default(); // Also null // Create number value let num_val = ByondValue::new_num(3.14); let from_f32: ByondValue = 42.0f32.into(); let from_bool: ByondValue = true.into(); // 1.0 // Create string value let str_val = ByondValue::new_str("Hello BYOND")?; let from_str: ByondValue = "test".try_into()?; let from_string: ByondValue = String::from("dynamic").try_into()?; // Create empty list let list_val = ByondValue::new_list()?; // Create reference with specific type let ref_val = ByondValue::new_ref(ValueType::Datum, ref_id); // Create global world reference let world_ref = ByondValue::new_global_ref(); ``` -------------------------------- ### Cache String IDs with byond_string! Macro Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Demonstrates using the `byond_string!` macro to cache string IDs for efficient access to BYOND variables, procs, and global calls. This avoids repeated string lookups. ```rust use byondapi::prelude::*; #[byondapi::bind] fn optimized_var_access(obj: ByondValue) -> Result { // String ID is looked up once and cached in a static let health: f32 = obj.read_number_id(byond_string!("health"))?; let max_health: f32 = obj.read_number_id(byond_string!("max_health"))?; // Multiple accesses reuse the cached ID for _ in 0..100 { let _ = obj.read_var_id(byond_string!("name"))?; } // Use with call_id for proc calls let result = obj.call_id(byond_string!("update"), &[])?; // Use with global calls let time = byondapi::global_call::call_global_id( byond_string!("world_time"), &[] )?; Ok(ByondValue::new_num(health / max_health)) } ``` -------------------------------- ### Create High-Performance Macro Binding with #[bind_macro] Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Generate DM macros instead of procs using #[bind_macro] for performance-critical operations. This bypasses proc call overhead. ```rust use byondapi::prelude::*; // Generates a DM #define macro instead of a proc #[byondapi::bind_macro] fn fast_multiply(a: ByondValue, b: ByondValue) -> Result { let num_a: f32 = a.try_into()?; let num_b: f32 = b.try_into()?; Ok(ByondValue::new_num(num_a * num_b)) } ``` -------------------------------- ### Use Stored BYOND References Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Demonstrates iterating through and using stored `RcByondValue` references. The BYOND reference count is decremented when `RcByondValue` is dropped. ```rust use byondapi::prelude::*; use byondapi::value::refcounted::RcByondValue; use std::sync::Mutex; // Store references that outlive the FFI call static STORED_REFS: Mutex> = Mutex::new(Vec::new()); #[byondapi::bind] fn use_stored_refs() -> Result { let refs = STORED_REFS.lock().unwrap(); for rc_ref in refs.iter() { // Deref to access ByondValue methods let name = rc_ref.read_string("name")?; println!("Stored object: {}", name); } // RcByondValue decrements refcount when dropped Ok(ByondValue::null()) } ``` -------------------------------- ### Store BYOND Reference with RcByondValue Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Shows how to store BYOND values that outlive the FFI boundary using reference counting. This increments the BYOND reference count. ```rust use byondapi::prelude::*; use byondapi::value::refcounted::RcByondValue; use std::sync::Mutex; // Store references that outlive the FFI call static STORED_REFS: Mutex> = Mutex::new(Vec::new()); #[byondapi::bind] fn store_reference(obj: ByondValue) -> Result { // Convert to reference-counted wrapper (increments BYOND refcount) let rc_value: RcByondValue = obj.into(); // Store for later use STORED_REFS.lock().unwrap().push(rc_value); Ok(ByondValue::null()) } ``` -------------------------------- ### Call Procs on BYOND Objects Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Invoke DM procs on BYOND objects from Rust code. Calls are non-blocking (waitfor=0). Supports calling by proc name or cached string ID, with single or multiple arguments. ```rust use byondapi::prelude::*; #[byondapi::bind("/mob/proc/rust_attack")] fn attack_target(src: ByondValue, target: ByondValue) -> Result { // Call proc by name let damage = src.call("calculate_damage", &[target])?; // Call with multiple arguments let result = target.call("take_damage", &[ damage, ByondValue::new_str("brute")?, src, ])?; // Call by cached string ID for performance let proc_id = byond_string!("update_health_hud"); src.call_id(proc_id, &[])?; Ok(result) } ``` -------------------------------- ### Modify BYOND Value Through Pointer Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Demonstrates reading and writing to a BYOND value using its pointer representation for pass-by-reference semantics. Ensure the input is a valid pointer. ```rust use byondapi::prelude::*; #[byondapi::bind] fn modify_through_pointer(ptr_value: ByondValue) -> Result { // Wrap in pointer type (fails if not actually a pointer) let pointer = ByondValuePointer::new(ptr_value)?; // Read the value the pointer points to let current_value = pointer.read()?; let current_string = current_value.get_string()?; // Modify and write back through the pointer let new_value = ByondValue::new_str(format!("Modified: {}", current_string))?; pointer.write(&new_value)?; Ok(ByondValue::null()) } ``` -------------------------------- ### Read and Write Object Variables Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Access and modify variables on BYOND objects (datums, atoms, etc.) using their references. Supports reading variables by name or cached string ID, and writing variables with new values. ```rust use byondapi::prelude::*; #[byondapi::bind("/datum/myobj/proc/rust_process")] fn process_object(src: ByondValue) -> Result { // Read variable by name let name_value = src.read_var("name")?; let name: String = name_value.get_string()?; // Helper methods for common types let health: f32 = src.read_number("health")?; let description: String = src.read_string("desc")?; let contents: Vec = src.read_list("contents")?; // Write variable let mut obj = src; let new_name = ByondValue::new_str("Updated Name")?; obj.write_var("name", &new_name)?; // Read/write by cached string ID for performance let health_id = byond_string!("health"); let current: f32 = src.read_number_id(health_id)?; obj.write_var_id(health_id, &ByondValue::new_num(current + 10.0))?; Ok(ByondValue::null()) } ``` -------------------------------- ### Handle BYONDAPI Errors with Result and Match Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Use the `Error` enum and `Result` pattern to handle errors from BYONDAPI operations. Match on specific error types like `NotAString` or `NonUtf8String`, and propagate other errors using the `?` operator. This pattern is useful for robustly interacting with BYOND values. ```rust use byondapi::prelude::*; use byondapi::Error; #[byondapi::bind] fn safe_operations(value: ByondValue) -> Result { // Match on specific error types match value.get_string() { Ok(s) => println!("Got string: {}", s), Err(Error::NotAString(_)) => println!("Not a string"), Err(Error::NonUtf8String) => println!("Invalid UTF-8"), Err(e) => return Err(e), } // Check BYOND errors match value.call("nonexistent_proc", &[]) { Err(Error::InvalidProc(name)) => { println!("Proc {:?} doesn't exist", name); } Err(Error::ByondError(e)) => { println!("BYOND error: {:?}", e.0); } _ => {} } // Use ? operator for propagation let name = value.read_string("name")?; let list = value.read_list("contents")?; Ok(ByondValue::null()) } ``` -------------------------------- ### Call Global BYOND Procs Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Invoke global DM procs that are not associated with a specific object from Rust code. Supports calling by proc name or cached string ID. ```rust use byondapi::prelude::*; use byondapi::global_call::{call_global, call_global_id}; #[byondapi::bind] fn trigger_global_event() -> Result { // Call global proc by name let result = call_global("announce_event", &[ ByondValue::new_str("Server message from Rust!")?, ])?; // Call by cached string ID for performance let proc_id = byond_string!("get_game_time"); let game_time = call_global_id(proc_id, &[])?; Ok(game_time) } ``` -------------------------------- ### ByondValue Type Checking Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Check the type of a ByondValue before operations using methods like is_null(), is_num(), is_str(), is_list(), is_ptr(), and is_true(). ```rust use byondapi::prelude::*; fn inspect_value(value: &ByondValue) { // Get raw type byte let type_byte = value.get_type(); // Type checking methods if value.is_null() { println!("Value is null"); } if value.is_num() { let num = value.get_number().unwrap(); println!("Number: {}", num); } if value.is_str() { let s = value.get_string().unwrap(); println!("String: {}", s); } if value.is_list() { let items = value.get_list_values().unwrap(); println!("List with {} items", items.len()); } if value.is_ptr() { println!("Value is a pointer"); } // Check truthiness (non-zero numbers, non-empty strings) if value.is_true() { println!("Value is truthy"); } } ``` -------------------------------- ### Extract Rust Types from ByondValue Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Use getter methods or the TryFrom trait to extract Rust types like numbers, booleans, strings, CStrings, reference IDs, and string IDs from a ByondValue. Ensure the ByondValue is of the expected type to avoid errors. ```rust use byondapi::prelude::*; use std::ffi::CString; fn extract_values(value: ByondValue) -> Result<(), byondapi::Error> { // Get number let num: f32 = value.get_number()?; let num_via_try: f32 = value.try_into()?; // Get boolean (non-zero = true) let boolean: bool = value.get_bool()?; let bool_via_try: bool = (&value).try_into()?; // Get string let string: String = value.get_string()?; let string_via_try: String = value.try_into()?; // Get CString (for FFI) let cstring: CString = value.get_cstring()?; // Get reference ID (for objects/datums) let ref_id: u32 = value.get_ref()?; // Get string ID (for string values) let str_id: u32 = value.get_strid()?; Ok(()) } ``` -------------------------------- ### Modify ByondValue In-Place Source: https://context7.com/spacestation13/byondapi-rs/llms.txt Modify existing ByondValue instances directly without allocating new values. Supports setting numbers, strings, string IDs (BYOND 516.1651+), and references. ```rust use byondapi::prelude::*; fn modify_value(value: &mut ByondValue) -> Result<(), byondapi::Error> { // Set to number value.set_number(100.0); // Set to string value.set_str("new value")?; // Set string by ID (BYOND 516.1651+) #[cfg(feature = "byond-516-1651")] { let str_id = byondapi::byond_string::str_id_of("cached_string")?; value.set_strid(str_id); } // Set reference value.set_ref(0x21, datum_ref_id); // 0x21 = Datum type Ok(()) } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.