fx_callback/lib.rs
1/*!
2
3
4[](https://crates.io/crates/fx-callback)
5[](./LICENSE)
6[](https://codecov.io/gh/yoep/fx-callback)
7
8A subscription based callback for data events that might occur within one or more structs.
9It is mainly used within the FX landscape to allow events to be published between multiple structs.
10
11## Example
12
13```rust
14use fx_callback::{Callback, MultiThreadedCallback, Subscriber, Subscription};
15
16/// The events of the struct that informs subscribers about changes to the data within the struct.
17#[derive(Debug, Clone, PartialEq)]
18enum MyEvent {
19 Foo,
20}
21
22/// The struct to which an interested subscriber can subscribe to.
23#[derive(Debug)]
24struct Example {
25 callbacks: MultiThreadedCallback<MyEvent>,
26}
27
28impl Example {
29 fn invoke_event(&self) {
30 self.callbacks.invoke(MyEvent::Foo);
31 }
32}
33
34impl Callback<MyEvent> for Example {
35 fn subscribe(&self) -> Subscription<MyEvent> {
36 self.callbacks.subscribe()
37 }
38
39 fn subscribe_with(&self, subscriber: Subscriber<MyEvent>) {
40 self.callbacks.subscribe_with(subscriber)
41 }
42}
43```
44
45## Usage
46
47### Subscription/event holder
48
49To get started with adding callbacks to your structs, add one of the implementations of the `Callback` trait.
50Make sure that the struct implements the `Debug` trait.
51
52```rust
53use fx_callback::{Callback, MultiThreadedCallback};
54
55#[derive(Debug)]
56pub struct MyStruct {
57 callbacks: MultiThreadedCallback<MyEvent>,
58}
59```
60
61Add the `Callback` trait implementation to your struct to allow adding callbacks.
62
63```rust
64impl Callback<MyEvent> for MyStruct {
65 fn subscribe(&self) -> Subscription<MyEvent> {
66 self.callbacks.subscribe()
67 }
68
69 fn subscribe_with(&self, subscriber: Subscriber<MyEvent>) {
70 self.callbacks.subscribe_with(subscriber)
71 }
72}
73```
74
75When you want to inform subscribers about a certain event, call the `invoke` method.
76
77```rust
78impl MyStruct {
79 pub fn invoke_event(&self) {
80 self.callbacks.invoke(MyEvent::Foo);
81 }
82}
83```
84
85### Subscriber
86
87The interested subscriber can subscribe to the interested event of a struct that implements the `Callback` trait.
88
89```rust
90use fx_callback::{Callback, MultiThreadedCallback, Subscriber, Subscription};
91use tokio::runtime::Runtime;
92
93fn main() {
94 let runtime = Runtime::new().unwrap();
95 let struct_with_callback = MyStruct::new();
96
97 let mut receiver = struct_with_callback.subscribe();
98 runtime.spawn(async move {
99 loop {
100 if let Some(event) = receiver.recv().await {
101 println!("Received event: {}", event);
102 } else {
103 break;
104 }
105 }
106 });
107
108 struct_with_callback.invoke_event();
109}
110```
111*/
112
113#[doc(inline)]
114pub use callback::*;
115
116mod callback;
117
118#[cfg(test)]
119pub(crate) mod tests {
120 use log::LevelFilter;
121 use log4rs::append::console::ConsoleAppender;
122 use log4rs::config::{Appender, Root};
123 use log4rs::encode::pattern::PatternEncoder;
124 use log4rs::Config;
125 use std::sync::Once;
126
127 static INIT: Once = Once::new();
128
129 /// Initializes the logger with the specified log level.
130 #[macro_export]
131 macro_rules! init_logger {
132 ($level:expr) => {
133 crate::tests::init_logger_level($level)
134 };
135 () => {
136 crate::tests::init_logger_level(log::LevelFilter::Trace)
137 };
138 }
139
140 /// Initializes the logger with the specified log level.
141 pub(crate) fn init_logger_level(level: LevelFilter) {
142 INIT.call_once(|| {
143 log4rs::init_config(Config::builder()
144 .appender(Appender::builder().build("stdout", Box::new(ConsoleAppender::builder()
145 .encoder(Box::new(PatternEncoder::new("\x1B[37m{d(%Y-%m-%d %H:%M:%S%.3f)}\x1B[0m {h({l:>5.5})} \x1B[35m{I:>6.6}\x1B[0m \x1B[37m---\x1B[0m \x1B[37m[{T:>15.15}]\x1B[0m \x1B[36m{t:<60.60}\x1B[0m \x1B[37m:\x1B[0m {m}{n}")))
146 .build())))
147 .build(Root::builder().appender("stdout").build(level))
148 .unwrap())
149 .unwrap();
150 })
151 }
152}