Skip to main content

event_notify/
event.rs

1trait ListenFn<P, N, R>: 'static + Send + Sync + Fn(P, Option<&N>) -> R {}
2
3impl<T, P, N, R> ListenFn<P, N, R> for T where
4    T: 'static + ?Sized + Send + Sync + Fn(P, Option<&N>) -> R
5{
6}
7
8pub struct Event<P, R> {
9    l: Listen<P, R>,
10}
11
12impl<P, R> Event<P, R> {
13    #[inline]
14    pub fn listen<F>(f: F) -> Listen<P, R>
15    where
16        F: Fn(P, Option<&Next<P, R>>) -> R + Send + Sync + 'static,
17    {
18        Listen::new(f)
19    }
20
21    #[inline]
22    pub fn fire(&self, args: P) -> R {
23        let n = self.l.next.as_ref().map(|n| n.as_ref());
24        (self.l.f)(args, n)
25    }
26}
27
28pub struct Next<P, R> {
29    l: Listen<P, R>,
30}
31
32impl<P, R> Next<P, R> {
33    #[inline]
34    fn new(l: Listen<P, R>) -> Self {
35        Self { l }
36    }
37
38    #[inline]
39    pub fn forward(&self, args: P) -> R {
40        let n = self.l.next.as_ref().map(|n| n.as_ref());
41        (self.l.f)(args, n)
42    }
43
44    #[inline]
45    fn link(&mut self, next: Self) {
46        if let Some(n) = self.l.next.as_mut() {
47            n.link(next);
48        } else {
49            self.l.next = Some(Box::new(next));
50        }
51    }
52}
53
54pub struct Listen<P, R> {
55    f: Box<dyn ListenFn<P, Next<P, R>, R>>,
56    next: Option<Box<Next<P, R>>>,
57}
58
59impl<P, R> Listen<P, R> {
60    #[inline]
61    fn new<F>(f: F) -> Self
62    where
63        F: Fn(P, Option<&Next<P, R>>) -> R + Send + Sync + 'static,
64    {
65        Self {
66            f: Box::new(f),
67            next: None,
68        }
69    }
70
71    #[inline]
72    pub fn listen<F>(mut self, f: F) -> Self
73    where
74        F: Fn(P, Option<&Next<P, R>>) -> R + Send + Sync + 'static,
75    {
76        let next = Next::new(Self::new(f));
77        if let Some(n) = self.next.as_mut() {
78            n.link(next);
79        } else {
80            self.next = Some(Box::new(next));
81        }
82        self
83    }
84
85    #[inline]
86    pub fn finish(self) -> Event<P, R> {
87        Event { l: self }
88    }
89}
90
91#[test]
92fn test_event() {
93    let simple1 = Event::<i32, i32>::listen(|args: i32, next| {
94        if args == 100 {
95            return args;
96        }
97        if let Some(next) = next {
98            next.forward(args)
99        } else {
100            1 * args
101        }
102    })
103    .listen(|args: i32, next| {
104        if args == 200 {
105            return args;
106        }
107        if let Some(next) = next {
108            next.forward(args)
109        } else {
110            2 * args
111        }
112    })
113    .listen(|args: i32, next| {
114        if args == 300 {
115            return args;
116        }
117        if let Some(next) = next {
118            next.forward(args)
119        } else {
120            3 * args
121        }
122    })
123    .finish();
124
125    assert_eq!(simple1.fire(10), 30);
126    assert_eq!(simple1.fire(100), 100);
127    assert_eq!(simple1.fire(300), 300);
128}
129
130#[test]
131fn test_event_single_listener() {
132    let event = Event::<i32, i32>::listen(|args, _next| args * 2).finish();
133
134    assert_eq!(event.fire(5), 10);
135    assert_eq!(event.fire(21), 42);
136}
137
138#[test]
139fn test_event_no_listener() {
140    // Single listener with no chained next (next = None)
141    let event = Event::<i32, i32>::listen(|args, next| {
142        assert!(next.is_none());
143        args * 3
144    })
145    .finish();
146
147    assert_eq!(event.fire(7), 21);
148}
149
150#[test]
151fn test_event_chained() {
152    // Extended chain: 4 listeners, value passes through
153    let event = Event::<i32, i32>::listen(|args: i32, next| {
154        if let Some(next) = next {
155            next.forward(args + 1)
156        } else {
157            args
158        }
159    })
160    .listen(|args: i32, next| {
161        if let Some(next) = next {
162            next.forward(args + 2)
163        } else {
164            args
165        }
166    })
167    .listen(|args: i32, next| {
168        if let Some(next) = next {
169            next.forward(args + 3)
170        } else {
171            args
172        }
173    })
174    .listen(|args: i32, _next| args + 4)
175    .finish();
176
177    // 10 + 1 + 2 + 3 + 4 = 20
178    assert_eq!(event.fire(10), 20);
179    // 0 + 1 + 2 + 3 + 4 = 10
180    assert_eq!(event.fire(0), 10);
181}
182
183#[test]
184fn test_event_chain_broken() {
185    // Middle listener does not forward, breaking the chain
186    let event = Event::<i32, String>::listen(|args: i32, next| {
187        if let Some(next) = next {
188            next.forward(args)
189        } else {
190            "end".to_string()
191        }
192    })
193    .listen(|args: i32, _next| {
194        // Does not forward, chain breaks here
195        format!("broken at {}", args)
196    })
197    .listen(|_args: i32, _next| unreachable!("this listener should never be called"))
198    .finish();
199
200    assert_eq!(event.fire(42), "broken at 42");
201}
202
203#[test]
204fn test_event_with_data() {
205    // Parameterized event with String data
206    let event = Event::<String, usize>::listen(|args: String, next| {
207        if let Some(next) = next {
208            next.forward(args)
209        } else {
210            args.len()
211        }
212    })
213    .listen(|args: String, _next| args.len() * 2)
214    .finish();
215
216    assert_eq!(event.fire("hello".to_string()), 10);
217    assert_eq!(event.fire("rust".to_string()), 8);
218}
219
220#[test]
221fn test_event_multiple_fire() {
222    // Fire same event multiple times, should produce same results
223    let event = Event::<i32, i32>::listen(|args: i32, next| {
224        if let Some(next) = next {
225            next.forward(args * 2)
226        } else {
227            args
228        }
229    })
230    .listen(|args: i32, _next| args + 1)
231    .finish();
232
233    // (5 * 2) + 1 = 11
234    assert_eq!(event.fire(5), 11);
235    // (5 * 2) + 1 = 11 (same args, same result)
236    assert_eq!(event.fire(5), 11);
237    // (3 * 2) + 1 = 7
238    assert_eq!(event.fire(3), 7);
239    assert_eq!(event.fire(10), 21);
240}