1use {
4 crate::_private::PollableId,
5 futures_util::{io::AsyncRead, AsyncWrite},
6 std::{
7 future::poll_fn,
8 io::{self, ErrorKind, IoSlice, IoSliceMut, Read, Write},
9 os::fd::{AsFd, AsRawFd},
10 pin::Pin,
11 task::{ready, Context, Poll},
12 },
13 thiserror::Error,
14 uapi::c,
15};
16
17#[derive(Debug, Error)]
18enum AsyncError {
19 #[error("Could not retrieve the file description flags")]
20 GetFl(#[source] io::Error),
21 #[error("Could not set the file description flags")]
22 SetFl(#[source] io::Error),
23 #[error("This configuration has already been destroyed")]
24 Destroyed,
25 #[error("The compositor could not create the necessary data structures: {0}")]
26 CompositorSetup(String),
27 #[error("Could not poll the file description: {0}")]
28 Poll(String),
29}
30
31impl From<AsyncError> for io::Error {
32 fn from(value: AsyncError) -> Self {
33 io::Error::new(ErrorKind::Other, value)
34 }
35}
36
37pub struct Async<T> {
39 id: PollableIdWrapper,
40 t: Option<T>,
41}
42
43impl<T> Unpin for Async<T> {}
44
45struct PollableIdWrapper {
46 id: PollableId,
47}
48
49impl Drop for PollableIdWrapper {
50 fn drop(&mut self) {
51 get!().remove_pollable(self.id);
52 }
53}
54
55impl<T> Async<T>
56where
57 T: AsFd,
58{
59 pub fn new(t: T) -> Result<Self, io::Error> {
65 Ok(Self::new_(t)?)
66 }
67
68 fn new_(t: T) -> Result<Self, AsyncError> {
69 let fd = t.as_fd();
70 let fl = uapi::fcntl_getfl(fd.as_raw_fd())
71 .map_err(|e| AsyncError::GetFl(io::Error::from_raw_os_error(e.0)))?;
72 uapi::fcntl_setfl(fd.as_raw_fd(), fl | c::O_NONBLOCK)
73 .map_err(|e| AsyncError::SetFl(io::Error::from_raw_os_error(e.0)))?;
74 let id = get!(Err(AsyncError::Destroyed))
75 .create_pollable(fd.as_raw_fd())
76 .map_err(AsyncError::CompositorSetup)?;
77 Ok(Self {
78 id: PollableIdWrapper { id },
79 t: Some(t),
80 })
81 }
82}
83
84impl<T> Async<T> {
85 pub fn unwrap(self) -> T {
89 self.t.unwrap()
90 }
91
92 fn poll_(&self, writable: bool, cx: &mut Context<'_>) -> Poll<Result<(), AsyncError>> {
93 get!(Poll::Ready(Err(AsyncError::Destroyed)))
94 .poll_io(self.id.id, writable, cx)
95 .map_err(AsyncError::Poll)
96 }
97
98 async fn poll(&self, writable: bool) -> Result<(), io::Error> {
99 poll_fn(|cx| self.poll_(writable, cx)).await?;
100 Ok(())
101 }
102
103 pub async fn readable(&self) -> Result<(), io::Error> {
105 self.poll(false).await
106 }
107
108 pub async fn writable(&self) -> Result<(), io::Error> {
110 self.poll(true).await
111 }
112}
113
114impl<T> AsRef<T> for Async<T> {
115 fn as_ref(&self) -> &T {
116 self.t.as_ref().unwrap()
117 }
118}
119
120impl<T> AsMut<T> for Async<T> {
121 fn as_mut(&mut self) -> &mut T {
122 self.t.as_mut().unwrap()
123 }
124}
125
126fn poll_io<T, R>(
127 slf: &mut Async<T>,
128 writable: bool,
129 cx: &mut Context<'_>,
130 mut f: impl FnMut(&mut Async<T>) -> io::Result<R>,
131) -> Poll<io::Result<R>> {
132 loop {
133 ready!(slf.poll_(writable, cx))?;
134 match f(slf) {
135 Err(e) if e.kind() == ErrorKind::WouldBlock => {}
136 res => return Poll::Ready(res),
137 }
138 }
139}
140
141impl<T> AsyncRead for Async<T>
142where
143 T: Read,
144{
145 fn poll_read(
146 self: Pin<&mut Self>,
147 cx: &mut Context<'_>,
148 buf: &mut [u8],
149 ) -> Poll<io::Result<usize>> {
150 poll_io(self.get_mut(), false, cx, |slf| slf.as_mut().read(buf))
151 }
152
153 fn poll_read_vectored(
154 self: Pin<&mut Self>,
155 cx: &mut Context<'_>,
156 bufs: &mut [IoSliceMut<'_>],
157 ) -> Poll<io::Result<usize>> {
158 poll_io(self.get_mut(), false, cx, |slf| {
159 slf.as_mut().read_vectored(bufs)
160 })
161 }
162}
163
164impl<T> AsyncWrite for Async<T>
165where
166 T: Write,
167{
168 fn poll_write(
169 self: Pin<&mut Self>,
170 cx: &mut Context<'_>,
171 buf: &[u8],
172 ) -> Poll<io::Result<usize>> {
173 poll_io(self.get_mut(), true, cx, |slf| slf.as_mut().write(buf))
174 }
175
176 fn poll_write_vectored(
177 self: Pin<&mut Self>,
178 cx: &mut Context<'_>,
179 bufs: &[IoSlice<'_>],
180 ) -> Poll<io::Result<usize>> {
181 poll_io(self.get_mut(), true, cx, |slf| {
182 slf.as_mut().write_vectored(bufs)
183 })
184 }
185
186 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
187 poll_io(self.get_mut(), true, cx, |slf| slf.as_mut().flush())
188 }
189
190 fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
191 self.get_mut().t.take();
192 Poll::Ready(Ok(()))
193 }
194}