62个版本
0.4.0-alpha.5 | 2021年1月18日 |
---|---|
0.3.0-alpha.6 | 2023年6月21日 |
0.3.0-alpha.5 | 2023年3月14日 |
0.3.0-alpha.4 | 2021年9月8日 |
0.0.22 | 2019年11月13日 |
#124 in 异步
4,112 每月下载量
用于 39 个crate(5直接)
43KB
766 行
ghost_actor
GhostActor使使用Actor模型实现异步/并发代码变得简单、直观和符合习惯。
GhostActor仅使用安全代码,并且对futures执行器不可知—使用tokio、futures、async-std,你想要什么都可以。以下示例使用tokio。
它做什么?
The GhostActor struct is a 'static + Send + Sync
cheaply clone-able handle for managing rapid, efficient, sequential, mutable access to internal state data.
使用原始类型
// set our initial state
let (a, driver) = GhostActor::new(42_u32);
// spawn the driver--using tokio here as an example
tokio::task::spawn(driver);
// invoke some logic on the internal state (just reading here)
let result: Result<u32, GhostError> = a.invoke(|a| Ok(*a)).await;
// assert the result
assert_eq!(42, result.unwrap());
最佳实践:内部状态在新类型中
当你有一个内部状态结构体,并用GhostActor的新类型包装时,GhostActor最容易处理
struct InnerState {
age: u32,
name: String,
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Person(GhostActor<InnerState>);
impl Person {
pub fn new(age: u32, name: String) -> Self {
let (actor, driver) = GhostActor::new(InnerState { age, name });
tokio::task::spawn(driver);
Self(actor)
}
pub async fn birthday(&self) -> String {
self.0.invoke(|inner| {
inner.age += 1;
let msg = format!(
"Happy birthday {}, you are {} years old.",
inner.name,
inner.age,
);
<Result::<String, GhostError>>::Ok(msg)
}).await.unwrap()
}
}
let bob = Person::new(42, "Bob".to_string());
assert_eq!(
"Happy birthday Bob, you are 43 years old.",
&bob.birthday().await,
);
使用特性和(GhostFuture)提供动态actor类型
pub trait Fruit {
// until async traits are available in rust, you can use GhostFuture
fn eat(&self) -> GhostFuture<String, GhostError>;
// allows implementing clone on BoxFruit
fn box_clone(&self) -> BoxFruit;
}
pub type BoxFruit = Box<dyn Fruit>;
impl Clone for BoxFruit {
fn clone(&self) -> Self {
self.box_clone()
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Banana(GhostActor<u32>);
impl Banana {
pub fn new() -> BoxFruit {
let (actor, driver) = GhostActor::new(0);
tokio::task::spawn(driver);
Box::new(Self(actor))
}
}
impl Fruit for Banana {
fn eat(&self) -> GhostFuture<String, GhostError> {
let fut = self.0.invoke(|count| {
*count += 1;
<Result<u32, GhostError>>::Ok(*count)
});
// 'resp()' is a helper function that builds a GhostFuture
// from any other future that has a matching Output.
resp(async move {
Ok(format!("ate {} bananas", fut.await.unwrap()))
})
}
fn box_clone(&self) -> BoxFruit {
Box::new(self.clone())
}
}
// we could implement a similar 'Apple' struct
// that could be interchanged here:
let fruit: BoxFruit = Banana::new();
assert_eq!("ate 1 bananas", &fruit.eat().await.unwrap());
自定义GhostActor错误类型
函数GhostActor::invoke()
接受一个泛型错误类型。唯一的要求是它必须实现From<GhostError>
#[derive(Debug)]
struct MyError;
impl std::error::Error for MyError {}
impl std::fmt::Display for MyError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl From<GhostError> for MyError {
fn from(_: GhostError) -> Self {
Self
}
}
let (actor, driver) = GhostActor::new(42_u32);
tokio::task::spawn(driver);
assert_eq!(42, actor.invoke(|inner| {
<Result<u32, MyError>>::Ok(*inner)
}).await.unwrap());
代码示例
- Bounce:
cargo run --example bounce
贡献
此仓库使用cargo-task
。
cargo install cargo-task
cargo task
依赖
~1MB
~20K SLoC