1 unstable release
| 0.1.0 | Nov 12, 2025 |
|---|
#921 in Data structures
40KB
865 lines
Advanced Architecture (ADAR)
Adar is a collection of architectural tools that help you write more readable and performant code.
Disclaimer: This crate uses some
unsafecode. Please refer to the comments in the source code for details. (PRs are welcome to convert it to safe code)
Registry
Registry is a container that lets you control the lifetime of elements through an Entry struct returned after calling Registry::register(). Entry cannot be cloned, but it can be cast to a generic type using Entry::as_generic(), which makes it possible to store entries from multiple registries in a single container. Registry can be cloned and behaves like an Arc. Whenever the data is mutated, an internal RwLock is locked. You can also run code when an element is removed by using the set_remove_callback() callback.
Example
use adar_registry::prelude::*;
struct MenuItem(pub &'static str);
struct StyleSheet(pub &'static str);
fn main() {
// Original website setup
let menu = Registry::<MenuItem>::new();
let styles = Registry::<StyleSheet>::new();
let mut website_store = vec![];
website_store.push(menu.register(MenuItem("Home")).as_generic());
website_store.push(menu.register(MenuItem("About")).as_generic());
website_store.push(styles.register(StyleSheet("website.css")).as_generic());
print_state("Original website", &menu, &styles);
// Loading an extension which registers new resources
let mut extension_store = vec![];
extension_store.push(menu.register(MenuItem("Weather")).as_generic());
extension_store.push(menu.register(MenuItem("News")).as_generic());
extension_store.push(styles.register(StyleSheet("extension.css")).as_generic());
print_state("After extension is loaded", &menu, &styles);
// Unloading the extension
drop(extension_store);
print_state("After extension is unloaded", &menu, &styles);
}
fn print_state(step: &'static str, menu: &Registry<MenuItem>, styles: &Registry<StyleSheet>) {
println!("{}", step);
println!("\tMenu:");
for (e, item) in menu.read().iter() {
println!("\t\t{}: {}", e, item.0);
}
println!("\tStyleSheets:");
for (e, item) in styles.read().iter() {
println!("\t\t{}: {}", e, item.0);
}
}// All of the different kind of resources registered by the extension are unloaded here
Click to see the output
>> cargo run --example registry_extension
Original website
Menu:
0: Home
1: About
StyleSheets:
0: website.css
After extension is loaded
Menu:
0: Home
1: About
2: Weather
3: News
StyleSheets:
0: website.css
1: extension.css
After extension is unloaded
Menu:
0: Home
1: About
StyleSheets:
0: website.css
RegistryMap
RegistryMap is similar to Registry. But you need to identify each element in the registry with a key. The key need to be provided during register() and you can later get the elements using get() or get(). RegistryMap uses a BTreeMap internally.
Example
use adar_registry::prelude::*;
trait EndPoint {
fn execute(&self);
}
struct GetUser;
impl EndPoint for GetUser {
fn execute(&self) {
println!("Getting user");
}
}
fn main() {
let registry = RegistryMap::<&'static str, Box<dyn EndPoint + Send + Sync + 'static>>::new();
let _entry = registry.register("get_user", Box::new(GetUser));
registry.read().get(&"get_user").unwrap().execute();
}
Click to see the output
>> cargo run --example registry_map
Getting user
Event
Event is a lightweight wrapper around Registry. It provides an implementation of an event/observer architecture.
Please note that during event dispatch the Registry remains locked. This means that you cannot add elements to the registry from the callbacks. Also keep your observers lightweight!
Example
use adar_registry::prelude::*;
fn main() {
// Create an event and register two observers.
let event: Event<(u32, String)> = Event::new();
let _entry1 = event.register_observer(|data: &(u32, String)| {
println!("Observer #1 called: {:?}", data);
});
let entry2 = event.register_observer(|data: &(u32, String)| {
println!("Observer #2 called: {:?}", data);
});
// Since all entries are still in scope all the observers will be called.
event.dispatch((1, "First event".into()));
// After dropping entry2. The associated observer will be dropped.
drop(entry2);
event.dispatch((2, "Second event".into()));
}
Click to see the output
>> cargo run --example registry_extension
Observer #1 called: (1, "First event")
Observer #2 called: (1, "First event")
Observer #1 called: (2, "Second event")
TracedRegistry
TracedRegistry is an extension of Registry. It enables you to register multiple observers that handle registering or unregistering elements.
Example
use adar_registry::prelude::*;
fn main() {
let registry = TracedRegistry::<&'static str>::new();
let _observer = registry.register_observer(|(event, entry, value): &_| {
println!("{:?}, {:?}, {}", event, entry, value)
});
let foo = registry.register("foo");
let bar = registry.register("bar");
drop(foo);
let baz = registry.register("baz");
drop(bar);
drop(baz);
}
Click to see the output
>> cargo run --example registry_extension
Register, 0, foo
Register, 1, bar
UnRegister, 0, foo
Register, 2, baz
UnRegister, 1, bar
UnRegister, 2, baz