x11rb/xcb_ffi/
pending_errors.rs

1//! Management of pending errors for the XCB connection.
2//!
3//! We add our own error tracking ontop of what XCB already provides. For this reason, this module
4//! contains a struct for tracking requests that were send and also tracking errors that were
5//! received, but not yet given to the user of this library.
6
7use std::cmp::Reverse;
8use std::collections::{BinaryHeap, VecDeque};
9use std::sync::Mutex;
10
11use super::{Buffer, XCBConnection};
12use x11rb_protocol::SequenceNumber;
13
14#[derive(Debug, Default)]
15struct PendingErrorsInner {
16    in_flight: BinaryHeap<Reverse<SequenceNumber>>,
17    pending: VecDeque<(SequenceNumber, Buffer)>,
18}
19
20/// A management struct for pending X11 errors
21#[derive(Debug, Default)]
22pub(crate) struct PendingErrors {
23    inner: Mutex<PendingErrorsInner>,
24}
25
26impl PendingErrors {
27    pub(crate) fn append_error(&self, error: (SequenceNumber, Buffer)) {
28        self.inner.lock().unwrap().pending.push_back(error)
29    }
30
31    pub(crate) fn discard_reply(&self, sequence: SequenceNumber) {
32        self.inner.lock().unwrap().in_flight.push(Reverse(sequence));
33    }
34
35    pub(crate) fn get(&self, conn: &XCBConnection) -> Option<(SequenceNumber, Buffer)> {
36        let mut inner = self.inner.lock().unwrap();
37
38        // Check if we already have an element at hand
39        let err = inner.pending.pop_front();
40        if err.is_some() {
41            return err;
42        }
43
44        // Check if any of the still in-flight responses got a reply/error
45        while let Some(&Reverse(seqno)) = inner.in_flight.peek() {
46            let result = match conn.poll_for_reply(seqno) {
47                Err(()) => {
48                    // This request was not answered/errored yet, so later request will not
49                    // have answers as well.
50                    return None;
51                }
52                Ok(reply) => reply,
53            };
54
55            let seqno2 = inner.in_flight.pop();
56            assert_eq!(Some(Reverse(seqno)), seqno2);
57
58            if let Some(result) = result {
59                // Is this an error?
60                if result[0] == 0 {
61                    return Some((seqno, result));
62                } else {
63                    // It's a reply, just ignore it
64                }
65            }
66        }
67
68        None
69    }
70}