actixhandlermacro

Rust Docs


Helper macros for using Actix.

```rust use actix::Message; use actixhandlermacro::{actix_handler, Actor};

[derive(Actor)]

struct Example; type ExampleContext = actix::Context;

[derive(Message)]

[rtype(result = "String")]

struct Greeting { name: String, }

[actix_handler]

impl Example { fn greet(&self, message: Greeting, ctx: &ExampleContext) -> String { format!("Hello {}", message.name).tostring() } } ``` actorderive; expandaddr; expandimplhandlers; expandmethodhandlers; options; utils;

expandimplhandlers::expanditemimpl; options::{parseoptions, Options}; procmacro::TokenStream; quote::quote; syn::{parsemacroinput, AttributeArgs, DeriveInput, Item}; utils::compilation_error;

Allows writing Actix actors with impl blocks.

Motivation

Actix can be quite verbose when declaring handlers:

```rust use actix::Actor; use actix::Context; use actix::Handler; use actix::Message;

struct Example;

impl Actor for Example { type Context = Context; }

[derive(Message)]

[rtype(result = "String")]

struct Greeting { name: String }

impl Handler for Example { type Result = String;

fn handle(&mut self, msg: Greeting, ctx: &mut Context<Self>) -> Self::Result {
    unimplemented!()
}

} ```

actix_derive_macro reads an impl block and generates a bit of this code for each method.

Usage

```rust use actixhandlermacro::{Actor, actix_handler}; use actix::{Actor, Addr, Context, Message, System};

[derive(Actor)]

struct Example;

type ExampleContext = Context;

[derive(Clone, Message)]

[rtype(result = "String")]

struct Greeting { name: String }

[actix_handler]

impl Example { fn greet(&self, message: Greeting, ctx: &ExampleContext) -> String { format!("Hello {}", message.name).tostring() } }

fn example_usage() { let mut sys = System::new("actix-test-runtime"); let addr: Addr = Example {}.start();

sys.block_on(async move {
    let greeting = Greeting { name: "you".to_string() };
    // `Example` has its handler impl block
    let result = addr.send(greeting.clone()).await.ok().unwrap();
    assert_eq!(result, "Hello you");

    // An Addr trait is also expanded:
    let result = addr.greet(greeting.clone()).await.ok().unwrap();
    assert_eq!(result, "Hello you")
});

} ```

This will expand a Handler<Greeting> impl for each method in Example.

Actor ...Addr trait

It'll also output a trait GreetingAddr and its implementation for Addr<Example> with convenience methods:

ignore // Example output trait GreetingAddr { fn greet(self: &Self, msg: Greeting) -> actix::prelude::Request<Example, Greeting>; }

RecipientRequest

Optionally, the trait can use a actix::Recipient and return a actix::RecipientRequest.

```rust use actix::{Message}; use actixhandlermacro::{actix_handler, Actor};

[derive(Actor)]

struct Example; type ExampleContext = actix::Context;

[derive(Message)]

[rtype(result = "String")]

struct Greeting { name: String }

[actixhandler(userecipient)]

impl Example { fn greet(&self, message: Greeting, ctx: &ExampleContext) -> String { format!("Hello {}", message.name).tostring() } } ```

#[actix_handler(use_recipient)] will expand the GreetingAddr trait as:

skip // Example output trait GreetingAddr { fn greet(self: &Self, msg: Greeting) -> actix::RecipientRequest<Greeting>; }

A mock of the actor could be implemented as: ```skip use actix::Message; use actixhandlermacro::Actor;

[derive(Actor)]

struct Example;

[derive(Message)]

[rtype(result = "String")]

struct Greeting;

[derive(Actor)]

struct ExampleMock { mocker: actix::Addr>, }

impl GreetingAddr for ExampleMock { fn greet(self: &Self, msg: Greeting) -> actix::prelude::RecipientRequest { self.mocker.clone().recipient().send(msg) } } ```