Usage Guide
Relevant source files
This guide provides practical instructions for using the AXNS library to manage resources across namespaces. It covers how to define resources, create namespaces, access and modify resources, and advanced operations like sharing and resetting resources. For conceptual understanding of the AXNS architecture, see Core Concepts, and for deeper details on resource lifecycle, see Resource Lifecycle.
Defining Resources
The first step to using AXNS is defining your resources using the def_resource!
macro. This macro creates static resource instances with proper initialization and cleanup.
def_resource! {
/// A simple integer resource
pub static COUNTER: i32 = 0;
/// A more complex resource with custom type
pub static CONFIG: Configuration = Configuration::default();
}
The macro creates a static ResWrapper<T>
for each resource, providing methods to access and manipulate the resource within namespaces.
Sources: src/res.rs(L144 - L168)
Creating and Managing Namespaces
A namespace is a container for resource instances. Create a new namespace using the Namespace::new()
constructor:
let mut my_namespace = Namespace::new();
When using the thread-local feature, you can also access the current namespace through resource wrappers:
let counter_ref = COUNTER.current(); // Gets the resource in the current namespace
Sources: src/lib.rs(L16 - L59)
flowchart TD A["Application Code"] B["Create Namespace"] C["Namespace::new()"] D["Define Resources"] E["def_resource! macro"] F["Access Resources"] G["resource.get(&ns)"] H["resource.get_mut(&mut ns)"] I["resource.current()"] A --> B A --> D A --> F B --> C D --> E F --> G F --> H F --> I
Basic Resource Access
AXNS provides several methods to access resources within namespaces:
Read-only Access
To get a reference to a resource in a namespace:
// Get reference to the resource in the specific namespace
let counter = COUNTER.get(&my_namespace);
Mutable Access
To modify a resource in a namespace:
// Get mutable reference if the resource isn't shared
if let Some(counter) = COUNTER.get_mut(&mut my_namespace) {
*counter += 1;
}
Note that get_mut()
returns Option<&mut T>
because it will return None
if the resource is shared with other namespaces.
Current Namespace Access
When the thread-local feature is enabled, you can access resources in the current namespace:
// Access resource in current namespace
let current_value = COUNTER.current();
Sources: src/res.rs(L69 - L92) tests/all.rs(L15 - L25)
sequenceDiagram participant Application as "Application" participant ResWrapperT as "ResWrapper<T>" participant Namespace as "Namespace" participant ResArcT as "ResArc<T>" Application ->> ResWrapperT: get(&namespace) ResWrapperT ->> Namespace: ns.get(self.res) Namespace ->> ResArcT: Returns ResArc<T> ResArcT ->> Application: Returns &T Application ->> ResWrapperT: get_mut(&mut namespace) ResWrapperT ->> Namespace: ns.get_mut(self.res) Namespace ->> ResArcT: Returns ResArc<T> ResArcT -->> Application: Returns Option<&mut T>
Advanced Operations
Sharing Resources Between Namespaces
To share a resource from one namespace to another:
let src_namespace = Namespace::new();
let mut dst_namespace = Namespace::new();
// Share the COUNTER resource from src to dst
COUNTER.share_from(&mut dst_namespace, &src_namespace);
This creates a shared reference to the same resource instance in both namespaces. Note that once shared, you won't be able to get mutable access to the resource in either namespace via get_mut()
.
Resetting Resources
To reset a resource in a namespace to its default value:
// Reset the COUNTER resource to its default value
COUNTER.reset(&mut my_namespace);
This discards the current resource instance and creates a new one with the default value specified in the def_resource!
macro.
Sources: src/res.rs(L94 - L104) tests/all.rs(L96 - L123)
Using Thread-Local Namespaces
When the thread-local
feature is enabled, AXNS provides thread-local namespaces for resource isolation:
// With thread-local feature enabled:
let counter = COUNTER.current(); // Gets from thread-local namespace
// You can implement the CurrentNs trait to define how thread-local
// namespaces are managed
The thread-local feature is particularly useful in multi-threaded applications where you want to isolate resources between threads.
Sources: src/lib.rs(L35 - L42) tests/all.rs(L40 - L159)
flowchart TD subgraph subGraph2["Resource Access Patterns"] A["Application Code"] F["Feature Check"] G["Current Thread?"] subgraph subGraph1["Feature: thread-local ON"] C["Thread 1 Namespace"] D["Thread 2 Namespace"] E["Thread 3 Namespace"] end subgraph subGraph0["Feature: thread-local OFF"] B["Global Namespace"] end end A --> F F --> B F --> G G --> C G --> D G --> E
Working with Custom Resource Types
AXNS can work with any type as a resource, including custom structs, atomics, and reference-counted types:
#![allow(unused)] fn main() { use std::sync::atomic::{AtomicUsize, Ordering}; struct Configuration { name: String, enabled: bool, } impl Configuration { fn default() -> Self { Self { name: "default".to_string(), enabled: false, } } } def_resource! { // Integer resource static COUNTER: i32 = 0; // Atomic for thread-safe access static ATOMIC_COUNTER: AtomicUsize = AtomicUsize::new(0); // Custom struct static CONFIG: Configuration = Configuration::default(); } // Working with atomic resources ATOMIC_COUNTER.current().fetch_add(1, Ordering::SeqCst); }
Sources: tests/all.rs(L1 - L38)
Best Practices
- Use appropriate resource types: For shared resources that need concurrent access, consider atomic types or other thread-safe structures.
- Minimize resource sharing: While AXNS makes it easy to share resources between namespaces, excessive sharing can reduce the benefits of namespace isolation.
- Reset when done: Reset resources when they're no longer needed to free up memory.
- Implement CurrentNs carefully: If using the thread-local feature, ensure your
CurrentNs
implementation correctly handles namespace lifecycle. - Check return value of get_mut(): Always check if
get_mut()
returnsSome
before attempting to modify a resource, as it may be shared.
flowchart TD A["Resource Definition"] B["Namespace Creation"] C["Resource Access"] D["Modify Resource?"] E["Is Shared?"] F["Use get_mut()"] G["Can't modify directly"] H["Options"] I["Unsupported markdown: list"] J["Unsupported markdown: list"] K["Unsupported markdown: list"] L["Use get()"] A --> B B --> C C --> D D --> E D --> L E --> F E --> G G --> H H --> I H --> J H --> K
For more detailed information on specific aspects of AXNS, refer to:
- Basic Resource Access for more examples of resource access patterns
- Sharing and Resetting Resources for advanced resource management techniques