1 个不稳定版本
使用旧的 Rust 2015
0.1.0 | 2016年6月11日 |
---|
#74 in #self
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个 关联类型
T
- 一个公有的枚举类型,用于发送到和从GenServer的消息。S
- actor将拥有和维护的状态。()
可在不需要管理状态的actor的情况下提供。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>
(可选)
处理发送给正在运行的演员的同步消息。
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>
(可选)
处理发送给正在运行的演员的异步消息。
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 回调中返回的 HandleResult
或 InitResult
中包含超时值来设置超时。
超时可以用于各种原因,但一个很好的例子是执行延迟初始化的模式。如果您的演员有长时间的初始化周期,您可以在 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