2 个版本
0.1.1 | 2020年3月24日 |
---|---|
0.1.0 | 2020年3月24日 |
#8 in #greeting
16KB
220 行
Bottles
Bottles 是一个 Rust 库,用于进行强类型消息传递,不使用枚举类型。这种方法的优点是添加新的消息类型非常容易,每个类型的尺寸不是所有类型中最大的(就像枚举类型那样)。
状态
这是一个非常早期的作品。
lib.rs
:
bottles
无枚举类型的类型化消息传递机制
这个 crate 允许将任何 'static 类型的消息放入瓶子中,然后可以将这些消息分发给该类型的订阅者。
这个 crate 中有两个主要类型:[Dispatcher](https://docs.rs/bottles/0.1.1/dispatcher/struct.Dispatcher.html) 和 [Queue](https://docs.rs/bottles/0.1.1/queue/struct.Queue.html)
Dispatcher
一个简单的类型与接收该类型消息的订阅者列表之间的映射。订阅者是一个闭包,它接受一个类型为 Rc<T>
的单个参数,每当分发具有该类型的消息时,它将被调用。
通常很难对没有任何 上下文 的消息做出反应,人们必须依赖于在闭包中捕获 Rc<RefCell<Context>>
以修改外部世界。提供的最简单的解决方案是使用 Queue
作为 Dispatcher
和回调本身之间的中间组件。
Queue
Queue 允许从一个或多个分发器收集消息,并在调用 Queue.poll
方法时将它们内部排队,该方法 允许 为所有订阅者提供“上下文”值。
Queue 订阅者是一个闭包,它恰好接受两个参数:对上下文字符变量的 &mut
引用和一个类型为 Rc<T>
的消息。
示例
向订阅者发送问候
use std::rc::Rc;
use bottles::Dispatcher;
struct Greeting {
greeting: String
}
fn callback(msg: Rc<Greeting>) {
println!("Greeting: {}", msg.greeting);
}
let mut dispatcher = Dispatcher::new();
// Every message type has to be registered explicitly
// It is a design choice to have a error when subscribing for a message type which is
// not registered by the particular Dispatcher, to error out as quickly as possible
dispatcher.register::<Greeting>();
dispatcher.subscribe(callback);
dispatcher.dispatch(Rc::new(Greeting { greeting: "Hello there!".to_string() }));
创建一个具有可变上下文的回调
use std::rc::Rc;
use bottles::{Dispatcher, Queue};
struct Add(i32);
struct Context {
state: i32
}
fn add(ctx: &mut Context, msg: Rc<Add>) {
ctx.state += msg.0;
}
let mut dispatcher = Dispatcher::new();
let mut queue = Queue::new();
queue.register::<Add>(&mut dispatcher);
queue.subscribe(&mut dispatcher, add);
// `queue` will receive the message and enqueue it for retrieval when polled.
dispatcher.dispatch(Rc::new(Add(42)));
let mut context = Context {
state: 0
};
// Very important: Queue has works by being polled, because this allows to pass a reference
// to the context without resorting to any interior mutability patterns.
queue.poll(&mut context);
assert_eq!(context.state, 42);