breadx/futures/
wait_for_reply.rs

1//               Copyright John Nunley, 2022.
2// Distributed under the Boost Software License, Version 1.0.
3//       (See accompanying file LICENSE or copy at
4//         https://www.boost.org/LICENSE_1_0.txt)
5
6use super::{CheckForError, WaitForReplyRaw};
7use crate::{
8    display::{AsyncDisplay, AsyncDisplayExt, Cookie},
9    Result,
10};
11use alloc::vec::Vec;
12use core::{
13    future::Future,
14    marker::PhantomData,
15    mem,
16    pin::Pin,
17    task::{Context, Poll},
18};
19use futures_util::FutureExt;
20use x11rb_protocol::x11_utils::TryParseFd;
21
22/// The future returned by the `wait_for_reply` function.
23pub struct WaitForReply<'this, Dpy: ?Sized, Reply> {
24    innards: Innards<'this, Dpy>,
25    _marker: PhantomData<Reply>,
26}
27
28enum Innards<'this, Dpy: ?Sized> {
29    Waiting(WaitForReplyRaw<'this, Dpy>),
30    Checking(CheckForError<'this, Dpy>),
31}
32
33impl<'this, Dpy: AsyncDisplay + ?Sized, Reply> WaitForReply<'this, Dpy, Reply> {
34    pub(crate) fn new(dpy: &'this mut Dpy, cookie: Cookie<Reply>) -> Self {
35        Self {
36            innards: if mem::size_of::<Reply>() == 0 {
37                Innards::Checking(dpy.check_for_error(cookie.sequence()))
38            } else {
39                Innards::Waiting(dpy.wait_for_reply_raw(cookie.sequence()))
40            },
41            _marker: PhantomData,
42        }
43    }
44
45    pub(crate) fn cannibalize(self) -> &'this mut Dpy {
46        match self.innards {
47            Innards::Waiting(innards) => innards.cannibalize(),
48            Innards::Checking(innards) => innards.cannibalize(),
49        }
50    }
51}
52
53impl<'this, Dpy: AsyncDisplay + ?Sized, Reply: TryParseFd + Unpin> Future
54    for WaitForReply<'this, Dpy, Reply>
55{
56    type Output = Result<Reply>;
57
58    fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Result<Reply>> {
59        let this = self.get_mut();
60
61        // determine how it goes down
62        match this.innards {
63            Innards::Waiting(ref mut wait_for_reply_raw) => {
64                match wait_for_reply_raw.poll_unpin(ctx) {
65                    Poll::Ready(Ok(reply)) => Poll::Ready({
66                        // try to resolve the reply
67                        reply.into_reply()
68                    }),
69                    Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
70                    Poll::Pending => Poll::Pending,
71                }
72            }
73            Innards::Checking(ref mut check) => check.poll_unpin(ctx).map_ok(|()| {
74                Reply::try_parse_fd(&[], &mut Vec::new())
75                    .unwrap_or_else(|_| unreachable!())
76                    .0
77            }),
78        }
79    }
80}