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