Skip to content
This repository has been archived by the owner on Sep 22, 2020. It is now read-only.

More advanced macros #2

Open
callym opened this issue Nov 16, 2017 · 5 comments
Open

More advanced macros #2

callym opened this issue Nov 16, 2017 · 5 comments

Comments

@callym
Copy link
Contributor

callym commented Nov 16, 2017

I implemented a #[handler] macro to allow you to tag functions as a handler for a type, and generate the necessary code implementing the Handler trait for the type.
Is this useful?

It'd require Nightly because it depends on feature(proc_macro), but that can be feature-gated, so the custom derives would still work on Stable.

#[handler]
impl SumActor {
    #[handle(Sum)]
    fn sum(&mut self, message: Sum, _: &mut Context<Self>) -> Response<Self, Sum> {
        println!("{}", message.0 + message.1);
        Self::reply(message.0 + message.1)
    }
}

Which would expand to:

impl SumActor {
    fn sum(&mut self, message: Sum, _: &mut Context<Self>) -> Response<Self, Sum> {
        println!("{}", message.0 + message.1);
        Self::reply(message.0 + message.1)
    }
}

impl Handler<Sum> for SumActor {
    fn handle(&mut self, message: Sum, context: &mut Context<Self>) -> Response<Self, Sum> {
        self.sum(message, context)
    }
}
@fafhrd91
Copy link
Member

i see handler something like:

#[derive(Message)]
#[response(usize)]
struct Sum {
  a: usize,
  b: usize,
}

#[handler]
impl SumActor {
    #[handle(Sum)]
    fn sum(&mut self, a: usize, b: usize) -> usize {
        println!("{}", a + b);
        a + b
    }
}

expands to:

impl SumActor {
    fn sum(&mut self, a: usize, b: usize) -> usize {
        println!("{}", a + b);
        a + b
    }
}

impl Handler<Sum> for SumActor {
    fn handle(&mut self, message: Sum, context: &mut Context<Self>) -> Response<Self, Sum> {
        Self::reply(self.sum(message.a, message.b))
    }
}

@callym
Copy link
Contributor Author

callym commented Nov 22, 2017

In your example, how would you go from message: Sum to a: usize, b: usize in more complex cases, such as Structs, where you can't simply unwrap the type.

What about:

#[handler]
impl VectorActor {
    #[handle(Sum)]
    fn magnitude(&mut self, message: Sum) -> usize {
        sum.0 + sum.1
    }
}

With the expansion being:

impl Handler<Sum> for SumActor {
    fn handle(&mut self, message: Sum, context: &mut Context<Self>) -> Response<Self, Sum> {
        Self::reply(self.sum(message))
    }
}

For messages with () as a reply type, it can simply be:

#[handle(Message)]
fn reply(&mut self, message: Message) {
    // do work here
}

This still hides the context: &mut Context<Self> and Response<Self, ...> from the signature with slightly less magic involved.

@fafhrd91
Copy link
Member

I do not think tuple struct should be supported. and with normal struct we can destructor it by names, which we can take from handle definition. ctx could be optional param.

there is no point to introduce new macro just to reduce code by couple lines. and point of macro should be ergonomic.

@fafhrd91
Copy link
Member

90% use case coverage for new macro should be enough, but this 90% should really useful.
other 10% could use normal handler definition.

@callym
Copy link
Contributor Author

callym commented Nov 30, 2017

I've been thinking about this, and have something that works like

#[handler]
impl SomeActor {
    #[handle]
    fn add(&self, sum: Sum) -> usize {
        sum.0 + sum.1
    }

    #[handle]
    fn empty(&mut self, _: Empty, ctx: &mut Context<Self>) {
        // do whatever here
    }
}

The message type is taken from the handle fn arguments, return type is wrapped in Self::reply inside the macro, and ctx is optional. Both &self and &mut self work too.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants