#[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 arbitrary number of parameters and invocating 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!");