use core::ffi;
use std::{
marker::PhantomData,
mem::{size_of, MaybeUninit},
};
use ndk::android::looper::*;
pub trait LooperHandler {
fn on(&self, _fd: ffi::c_int) {}
}
#[repr(transparent)]
#[derive(Debug, PartialEq)]
pub struct Looper {
inner: *const ALooper,
}
impl Clone for Looper {
fn clone(&self) -> Self {
unsafe { ALooper_acquire(self.inner as _) };
Self { inner: self.inner }
}
}
impl Drop for Looper {
fn drop(&mut self) {
unsafe { ALooper_release(self.inner as _) }
}
}
impl Looper {
pub fn from_raw(inner: *mut ALooper) -> Option<Self> {
if !inner.is_null() {
Some(Self { inner })
} else {
None
}
}
pub fn current() -> Option<Self> {
let inner = unsafe { ALooper_forThread() };
Self::from_raw(inner)
}
pub fn prepare(opts: ffi::c_int) -> Option<Self> {
let inner = unsafe { ALooper_prepare(opts) };
Self::from_raw(inner)
}
pub fn add<T: LooperHandler>(&self, fd: ffi::c_int, data: &std::rc::Rc<T>) -> Result<LooperGuard<T>, i32> {
let weak = std::rc::Rc::downgrade(&data);
let data = weak.into_raw();
let ret = unsafe {
ALooper_addFd(
self.inner as _,
fd,
ALOOPER_POLL_CALLBACK,
ALOOPER_EVENT_INPUT as _,
Some(on_event::<T>),
data as _,
)
};
if ret == 1 {
Ok(LooperGuard {
fd,
data,
looper: self.clone(),
_t: PhantomData,
})
} else {
Err(ret)
}
}
fn del<T>(&self, fd: ffi::c_int, data: *const T) -> Result<(), i32> {
let ret = unsafe { ALooper_removeFd(self.inner as _, fd) };
let _ = unsafe { std::rc::Weak::from_raw(data) };
if ret == 1 {
Ok(())
} else {
Err(ret)
}
}
}
extern "C" fn on_event<T: LooperHandler>(fd: ffi::c_int, _events: ffi::c_int, data: *mut ffi::c_void) -> ffi::c_int {
let weak = unsafe { std::rc::Weak::from_raw(data as *const T) };
if let Some(data) = weak.upgrade() {
data.on(fd);
}
let _ = weak.into_raw();
1
}
pub struct LooperGuard<T> {
data: *const T,
fd: ffi::c_int,
looper: Looper,
_t: PhantomData<T>,
}
impl<T> Drop for LooperGuard<T> {
fn drop(&mut self) {
self.looper.del::<T>(self.fd, self.data).ok();
}
}
pub fn pipe<T>() -> (Sender<T>, Recver<T>) {
let mut msgpipe: [libc::c_int; 2] = [-1, -1];
unsafe {
if libc::pipe(msgpipe.as_mut_ptr()) != 0 {
panic!("could not create pipe: {}", std::io::Error::last_os_error());
}
}
(
Sender {
fd_write: msgpipe[1],
_t: PhantomData,
},
Recver {
fd_read: msgpipe[0],
_t: PhantomData,
},
)
}
#[derive(Debug)]
pub struct Recver<T> {
pub fd_read: ffi::c_int,
_t: PhantomData<T>,
}
impl<T: Sized> Recver<T> {
pub fn recv(&self) -> Result<T, i32> {
let mut buf = MaybeUninit::<T>::uninit();
loop {
match unsafe { libc::read(self.fd_read, buf.as_mut_ptr() as _, size_of::<T>()) } {
i if i == size_of::<T>() as isize => unsafe {
return Ok(buf.assume_init());
},
-1 => {
let err = std::io::Error::last_os_error();
if err.kind() != std::io::ErrorKind::Interrupted {
return Err(-1);
}
continue;
}
_ => {
return Err(-2);
}
}
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct Sender<T> {
pub fd_write: ffi::c_int,
pub _t: PhantomData<T>,
}
impl<T> Sender<T> {
pub fn send(&self, cmd: T) -> Result<(), i32> {
loop {
match unsafe { libc::write(self.fd_write, &cmd as *const _ as *const _, size_of::<T>()) } {
i if i == size_of::<T>() as isize => return Ok(()),
-1 => {
let err = std::io::Error::last_os_error();
if err.kind() != std::io::ErrorKind::Interrupted {
return Err(-1);
}
continue;
}
_ => {
return Err(-2);
}
}
}
}
}