tokio_i3ipc/
codec.rs

1//! Implements `tokio_codec`'s `Decoder` trait
2//!
3//! Using `EventCodec` to subscribe to [event::Event](../event/enum.Event.html)
4//! from i3:
5//!
6//! ```no_run
7//! # use tokio_stream::StreamExt;
8//! # use std::io;
9//! use tokio_i3ipc::{event::Subscribe, I3};
10//!
11//! #[tokio::main(flavor = "current_thread")]
12//! async fn main() -> io::Result<()> {
13//!     let mut i3 = I3::connect().await?;
14//!     i3.subscribe([Subscribe::Window]).await?;
15//!
16//!     let mut listener = i3.listen();
17//!     while let Some(event) = listener.next().await {
18//!         println!("{:#?}", event);
19//!     }
20//!     Ok(())
21//! }
22//! ```
23use bytes::{buf::Buf, BytesMut};
24use tokio_util::codec::Decoder;
25
26use i3ipc_types::{decode_event, event, MAGIC};
27
28use std::io;
29
30/// This codec only impls `Decoder` because it's only job is to read messages
31/// from i3 and turn them into frames of Events. All other interactions with i3
32/// over the IPC are simple send/receive operations. Events received will be
33/// relative to what was subscribed.
34pub struct EventCodec;
35
36impl Decoder for EventCodec {
37    type Error = io::Error;
38    type Item = event::Event;
39
40    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, io::Error> {
41        if src.len() > 14 {
42            if &src[0..6] != MAGIC.as_bytes() {
43                return Err(io::Error::new(
44                    io::ErrorKind::Other,
45                    format!("Expected 'i3-ipc' but received: {:?}", &src[0..6]),
46                ));
47            }
48            let payload_len = u32::from_ne_bytes([src[6], src[7], src[8], src[9]]) as usize;
49            let evt_type = u32::from_ne_bytes([src[10], src[11], src[12], src[13]]);
50            // ends at payload + original 14 bytes
51            let end_len = 14 + payload_len;
52            if src.len() < end_len {
53                Ok(None)
54            } else {
55                let evt = decode_event(evt_type, &src[14..end_len])?;
56                src.advance(end_len);
57                Ok(Some(evt))
58            }
59        } else {
60            Ok(None)
61        }
62    }
63}