Attribute Macro lunatic_macros::abstract_process

source ·
#[abstract_process]
Expand description

Add AbstractProcess behavior to the given struct implementation with minimum boilerplate code.

  • Use #[init], #[terminate], and #[handle_link_trapped] attributes to specify methods for implementing AbstractProcess.
  • Use #[handle_message] and #[handle_request] attributes to specify message and request handlers.

Specifying message types is unnecessary because the macro will create wrapper types for messages on all handlers. Handlers can take an arbitrary number of parameters and invoking them works the same as directly calling the method on the struct without spawning it as a process.

A trait is generated and defaults to private and follows the name of your type with Handler added as a suffix. To rename or change the visibility of the generated trait, you can use the trait_name and visbility arguments with #[abstract_process(trait_name = "MyHandler", visibility = pub)].

Examples

use lunatic::{
    abstract_process,
    process::{Message, ProcessRef, Request, StartProcess},
    Tag,
};

struct Counter(u32);

#[abstract_process]
impl Counter {
    #[init]
    fn init(_: ProcessRef<Self>, start: u32) -> Self {
        Self(start)
    }

    #[terminate]
    fn terminate(self) {
        println!("Shutdown process");
    }

    #[handle_link_trapped]
    fn handle_link_trapped(&self, tag: Tag) {
        println!("Link trapped");
    }

    #[handle_message]
    fn increment(&mut self) {
        self.0 += 1;
    }

    #[handle_request]
    fn count(&self) -> u32 {
        self.0
    }
}


let counter = Counter::start(5, None);
counter.increment();
assert_eq!(counter.count(), 6);

A more complicated example

use lunatic::{
    abstract_process,
    process::{Message, ProcessRef, Request, StartProcess},
}

struct A;

#[derive(serde::Serialize, serde::Deserialize)]
struct Person {
    name: String,
    age: u16,
}

#[abstract_process(trait_name = "AHandler", visibility = pub)]
impl A {
    #[init]
    fn init(_: ProcessRef<Self>, _: ()) -> A {
        A
    }

    #[hanlde_message]
    fn multiple_arguments(&self, a: u8, (b, c): (bool, char)) {
        assert_eq!(a, 5);
        assert_eq!(b, false);
        assert_eq!(c, 'a');
    }

    #[handle_request]
    fn unpack_struct(&self, Person { name, age }: Person) -> String {
        assert_eq!(name, "Mark");
        assert_eq!(age, 5);
        self.create_greeting(name)
    }

    fn create_greeting(&self, name: String) {
        format!("Hi {}!", name)
    }
}


let a = A::start_link((), None);

a.multiple_arguments(5, (false, 'a'));

let person = Person {
    name: "Mark".to_owned(),
    age: 4,
};

let greeting = a.unpack_struct(person);
assert_eq!(greeting, "Hi Mark!");