1use std::convert::TryInto;
11use std::fmt;
12use std::os::raw::c_void;
13use std::os::unix::io::RawFd;
14use std::ptr;
15use std::ptr::NonNull;
16use std::time::Duration;
17
18#[derive(Debug)]
21pub struct ThreadLooper {
22 _marker: std::marker::PhantomData<*mut ()>, foreign: ForeignLooper,
24}
25
26#[derive(Debug)]
28pub enum Poll {
29 Wake,
31 Callback,
33 Timeout,
35 Event {
37 ident: i32,
38 fd: RawFd,
39 events: i32,
40 data: *mut c_void,
41 },
42}
43
44#[derive(Debug, Copy, Clone)]
45pub struct LooperError;
46
47impl fmt::Display for LooperError {
48 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
49 write!(f, "Android Looper error")
50 }
51}
52
53impl std::error::Error for LooperError {}
54
55impl ThreadLooper {
56 pub fn for_thread() -> Option<Self> {
58 Some(Self {
59 _marker: std::marker::PhantomData,
60 foreign: ForeignLooper::for_thread()?,
61 })
62 }
63
64 fn poll_once_ms(&self, ms: i32) -> Result<Poll, LooperError> {
65 unsafe {
66 let mut fd: RawFd = -1;
67 let mut events: i32 = -1;
68 let mut data: *mut c_void = ptr::null_mut();
69 match ffi::ALooper_pollOnce(ms, &mut fd, &mut events, &mut data) {
70 ffi::ALOOPER_POLL_WAKE => Ok(Poll::Wake),
71 ffi::ALOOPER_POLL_CALLBACK => Ok(Poll::Callback),
72 ffi::ALOOPER_POLL_TIMEOUT => Ok(Poll::Timeout),
73 ffi::ALOOPER_POLL_ERROR => Err(LooperError),
74 ident if ident >= 0 => Ok(Poll::Event {
75 ident,
76 fd,
77 events,
78 data,
79 }),
80 _ => unreachable!(),
81 }
82 }
83 }
84
85 #[inline]
87 pub fn poll_once(&self) -> Result<Poll, LooperError> {
88 self.poll_once_ms(-1)
89 }
90
91 #[inline]
97 pub fn poll_once_timeout(&self, timeout: Duration) -> Result<Poll, LooperError> {
98 self.poll_once_ms(
99 timeout
100 .as_millis()
101 .try_into()
102 .expect("Supplied timeout is too large"),
103 )
104 }
105
106 fn poll_all_ms(&self, ms: i32) -> Result<Poll, LooperError> {
107 unsafe {
108 let mut fd: RawFd = -1;
109 let mut events: i32 = -1;
110 let mut data: *mut c_void = ptr::null_mut();
111 match ffi::ALooper_pollAll(ms, &mut fd, &mut events, &mut data) {
112 ffi::ALOOPER_POLL_WAKE => Ok(Poll::Wake),
113 ffi::ALOOPER_POLL_TIMEOUT => Ok(Poll::Timeout),
114 ffi::ALOOPER_POLL_ERROR => Err(LooperError),
115 ident if ident >= 0 => Ok(Poll::Event {
116 ident,
117 fd,
118 events,
119 data,
120 }),
121 _ => unreachable!(),
122 }
123 }
124 }
125
126 #[inline]
130 pub fn poll_all(&self) -> Result<Poll, LooperError> {
131 self.poll_all_ms(-1)
132 }
133
134 #[inline]
142 pub fn poll_all_timeout(&self, timeout: Duration) -> Result<Poll, LooperError> {
143 self.poll_all_ms(
144 timeout
145 .as_millis()
146 .try_into()
147 .expect("Supplied timeout is too large"),
148 )
149 }
150
151 pub fn as_foreign(&self) -> &ForeignLooper {
153 &self.foreign
154 }
155
156 pub fn into_foreign(self) -> ForeignLooper {
157 self.foreign
158 }
159}
160
161#[derive(Debug)]
163pub struct ForeignLooper {
164 ptr: NonNull<ffi::ALooper>,
165}
166
167unsafe impl Send for ForeignLooper {}
168unsafe impl Sync for ForeignLooper {}
169
170impl Drop for ForeignLooper {
171 fn drop(&mut self) {
172 unsafe { ffi::ALooper_release(self.ptr.as_ptr()) }
173 }
174}
175
176impl Clone for ForeignLooper {
177 fn clone(&self) -> Self {
178 unsafe {
179 ffi::ALooper_acquire(self.ptr.as_ptr());
180 Self { ptr: self.ptr }
181 }
182 }
183}
184
185impl ForeignLooper {
186 #[inline]
188 pub fn for_thread() -> Option<Self> {
189 NonNull::new(unsafe { ffi::ALooper_forThread() }).map(|ptr| unsafe { Self::from_ptr(ptr) })
190 }
191
192 #[inline]
197 pub unsafe fn from_ptr(ptr: NonNull<ffi::ALooper>) -> Self {
198 ffi::ALooper_acquire(ptr.as_ptr());
199 Self { ptr }
200 }
201
202 #[inline]
204 pub fn ptr(&self) -> NonNull<ffi::ALooper> {
205 self.ptr
206 }
207
208 pub fn wake(&self) {
210 unsafe { ffi::ALooper_wake(self.ptr.as_ptr()) }
211 }
212
213 pub unsafe fn add_fd(
219 &self,
220 fd: RawFd,
221 ident: i32,
222 event: i32,
223 data: *mut c_void,
224 ) -> Result<(), LooperError> {
225 match ffi::ALooper_addFd(self.ptr.as_ptr(), fd, ident, event, None, data) {
226 1 => Ok(()),
227 -1 => Err(LooperError),
228 _ => unreachable!(),
229 }
230 }
231
232 pub unsafe fn add_fd_with_callback(
241 &self,
242 fd: RawFd,
243 ident: i32,
244 event: i32,
245 callback: Box<dyn FnMut(RawFd) -> bool>,
246 ) -> Result<(), LooperError> {
247 extern "C" fn cb_handler(fd: RawFd, _events: i32, data: *mut c_void) -> i32 {
248 unsafe {
249 let cb: &mut Box<dyn FnMut(RawFd) -> bool> = &mut *(data as *mut _);
250 cb(fd) as i32
251 }
252 }
253 let data: *mut c_void = Box::into_raw(Box::new(callback)) as *mut _;
254 match ffi::ALooper_addFd(self.ptr.as_ptr(), fd, ident, event, Some(cb_handler), data) {
255 1 => Ok(()),
256 -1 => Err(LooperError),
257 _ => unreachable!(),
258 }
259 }
260}