1 个不稳定版本

使用旧的 Rust 2015

0.1.0 2016年6月11日

#74 in #self

MIT 许可证

23KB
411

Wonder 构建状态

一个受 Erlang/Elixir 启发的 Rust actor 库

要求

  • 稳定版/夜间版 Rust

快速入门

定义你的actor

pub struct MyActor;

实现GenServer特性

impl GenServer for MyActor {
    type T = MyMessage;
    type S = ();
    type E = MyError;

    fn init(&self, _tx: &ActorSender<Self::T>, state: &mut Self::S) -> InitResult<Self::E> {
      // initialization implementation
      Ok(None)
    }

    // Implement overrides for default implementations for additional callbacks
}

启动你的actor

use wonder::actor;

fn main() {
    let actor = actor::Builder::new(MyActor).start(()).unwrap();
}

GenServer特性

要创建一个GenServer actor,你需要创建一个结构体(可能是一个 单元结构体?)并实现GenServer特性。

struct MyActor;

关联类型

要实现GenServer特性,你需要定义3个 关联类型

  1. T - 一个公有的枚举类型,用于发送到和从GenServer的消息。
  2. S - actor将拥有和维护的状态。 () 可在不需要管理状态的actor的情况下提供。
  3. E - 一个公有的枚举类型,用于GenServer返回的错误。
struct MyState {
    pub initialized: bool,
}

#[derive(Debug)]
enum MyError {
    DirtyState,
}

#[derive(Debug)]
enum MyMessage {
    State(bool),
    GetState,
    SetState(bool),
}

impl GenServer for MyActor {
    type T = MyMessage;
    type S = MyState;
    // type S = (); // no state
    type E = MyError;

    // ... callbacks
}

注意:自定义错误和消息枚举都必须派生Debug特性。

回调函数

GenServer特性公开了4个回调函数;其中一个是必需的,其余三个有默认实现,因此它们是可选的。

init/3 -> InitResult<E>

类似于 GenServer:init/1

处理新创建的actor的初始化。与Elixir/Erlang中的进程初始化一样,这是一个阻塞调用。这个函数将在actor启动时调用一次。

init函数必须返回一个InitResult,它可以是Ok(Option<u64>)Err(E),其中E是自定义错误类型。可选的u64是actor的超时值(以毫秒为单位)。

impl GenServer for MyActor {
    type T = MyMessage;
    type S = MyState;
    type E = MyError;

    fn init(&self, atx: &ActorSender<Self::T>, state: &mut Self::S) -> InitResult<Self::E> {
        // perform some initialization
        Ok(None)
    }
}

参数

  • atx - 运行中的actor的通道发送者。这在Elixir/Erlang中相当于向“self”发送。
  • state - 对运行中的actor拥有的状态的可变引用。

注意:InitResult 类似于 Elixir 中 init/1 回调的返回元组;即 {:ok, state}{:stop, reason}

handle_call/5 -> HandleResult<T>(可选)

类似于 GenServer:handle_call/3

处理发送给正在运行的演员的同步消息。

impl GenServer for MyActor {
    type T = MyMessage;
    type S = MyState;
    type E = MyError;

    // ... other callbacks ...

    fn handle_call(&self, msg: Self::T, tx: &ActorSender<Self::T>,
        atx: &ActorSender<Self::T>, state: &mut Self::S) -> HandleResult<Self::T> {
        match msg {
            MyMessage::GetState => HandleResult::Reply(MyMessage::State(state.initialized), None),
            MyMessage::SetState(value) => {
                state.initialized = value;
                HandleResult::Reply(MyMessage::Ok, None)
            }
            _ => HandleResult::Stop(StopReason::Fatal(String::from("unhandled call")), None),
        }
    }
}

参数

  • tx - 启动演员的调用者的通道发送者。这相当于在 Elixir/Erlang 中发送到调用者的 PID。
  • atx - 与 init/3 相同。
  • state - 与 init/3 相同。

注意:HandleResult 类似于 Elixir/Erlang 中 handle_call/3 回调的返回元组。

handle_cast/4 -> HandleResult<T>(可选)

类似于 GenServer:handle_cast/2

处理发送给正在运行的演员的异步消息。

impl GenServer for MyActor {
    type T = MyMessage;
    type S = MyState;
    type E = MyError;

    // ... other callbacks ...

    fn handle_cast(&self, msg: Self::T, atx: &ActorSender<Self::T>, state: &mut Self::S) -> HandleResult<Self::T> {
        match msg {
            MyMessage::SetState(value) => {
                state.initialized = value;
                HandleResult::NoReply(None)
            },
            _ => HandleResult::NoReply(None)
        }
    }
}

参数

  • atx - 与 init/3 相同。
  • state - 与 init/3 相同。

注意:HandleResult 类似于 Elixir/Erlang 中 handle_cast/2 回调的返回元组。

handle_timeout/3 -> HandleResult<T>(可选)

类似于在 Elixir 中匹配 handle_info(:timeout, _state)

当设置超时并经过所需时间后会被调用。可以通过在 GenServer 回调中返回的 HandleResultInitResult 中包含超时值来设置超时。

超时可以用于各种原因,但一个很好的例子是执行延迟初始化的模式。如果您的演员有长时间的初始化周期,您可以在 handle_timeout 回调中立即超时并执行初始化。

impl GenServer for MyActor {
    type T = MyMessage;
    type S = MyState;
    type E = MyError;

    fn init(&self, atx: &ActorSender<Self::T>, state: &mut Self::S) -> InitResult<Self::E> {
        Ok(Some(0))
    }

    fn handle_timeout(&self, atx: &ActorSender<Self::T>, state: &mut Self::S) -> HandleResult<Self::T> {
        // long running function for late initialization
        HandleResult::NoReply(None)
    }
}

参数

  • atx - 与 init/3 相同。
  • state - 与 init/3 相同。

注意:HandleResult 类似于 Elixir/Erlang 中 handle_info/2 回调的返回元组。

作者

Jamie Winsor ([email protected])

依赖项

~0.6–1MB
~14K SLoC