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}
71