1use std::{
4 pin::Pin,
5 sync::{Arc, Mutex},
6 task::{Context, Poll},
7};
8
9use futures_channel::mpsc::{self, UnboundedReceiver};
10use futures_core::Stream;
11use futures_util::{StreamExt, stream::FusedStream};
12use glib::object::ObjectExt as _;
13
14use crate::{Bus, BusSyncReply, Message};
15
16#[derive(Debug)]
17pub struct BusStream {
18 bus: glib::WeakRef<Bus>,
19 receiver: UnboundedReceiver<Message>,
20}
21
22impl BusStream {
23 pub(crate) fn new(bus: &Bus) -> Self {
24 skip_assert_initialized!();
25
26 let mutex = Arc::new(Mutex::new(()));
27 let (sender, receiver) = mpsc::unbounded();
28
29 let _mutex_guard = mutex.lock().unwrap();
35 bus.set_sync_handler({
36 let sender = sender.clone();
37 let mutex = mutex.clone();
38
39 move |_bus, message| {
40 let _mutex_guard = mutex.lock().unwrap();
41
42 let _ = sender.unbounded_send(message.to_owned());
43
44 BusSyncReply::Drop
45 }
46 });
47
48 while let Some(message) = bus.pop() {
50 let _ = sender.unbounded_send(message);
51 }
52
53 Self {
54 bus: bus.downgrade(),
55 receiver,
56 }
57 }
58}
59
60impl Drop for BusStream {
61 fn drop(&mut self) {
62 if let Some(bus) = self.bus.upgrade() {
63 bus.unset_sync_handler();
64 }
65 }
66}
67
68impl Stream for BusStream {
69 type Item = Message;
70
71 fn poll_next(mut self: Pin<&mut Self>, context: &mut Context) -> Poll<Option<Self::Item>> {
72 self.receiver.poll_next_unpin(context)
73 }
74}
75
76impl FusedStream for BusStream {
77 fn is_terminated(&self) -> bool {
78 self.receiver.is_terminated()
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn test_bus_stream() {
88 crate::init().unwrap();
89
90 let bus = Bus::new();
91 let bus_stream = bus.stream();
92
93 let eos_message = crate::message::Eos::new();
94 bus.post(eos_message).unwrap();
95
96 let bus_future = StreamExt::into_future(bus_stream);
97 let (message, _) = futures_executor::block_on(bus_future);
98
99 match message.unwrap().view() {
100 crate::MessageView::Eos(_) => (),
101 _ => unreachable!(),
102 }
103 }
104}