adar-registry 0.2.0

Advanced Architecture (ADAR) is a collection of architectural tools that help you write more readable and performant code.
Documentation
  • Coverage
  • 71.59%
    63 out of 88 items documented1 out of 69 items with examples
  • Size
  • Source code size: 49.69 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 6.71 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 19s Average build duration of successful builds.
  • all releases: 19s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Repository
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • nandee95

Advanced Architecture (ADAR)

Crates.io Downloads Docs

Adar is a collection of architectural tools that help you write more readable and performant code.

Disclaimer: This crate uses some unsafe code. 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
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();
}
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()));
}
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);
}
Register, 0, foo
Register, 1, bar
UnRegister, 0, foo
Register, 2, baz
UnRegister, 1, bar
UnRegister, 2, baz