From 4f7010d6c321c02f42f9bf4c8ca309fbfc8ae100 Mon Sep 17 00:00:00 2001 From: John Nunley Date: Sun, 10 Nov 2024 20:04:40 -0800 Subject: [PATCH] feat: Add waker() method to AndroidAppWaker This commit adds a "waker()" method to AndroidAppWaker. It converts it into an `std::task::Waker`, which is the type of waker used by asynchronous tasks for scheduling. The goal is to allow AndroidAppWaker to be easily used to set up an asynchronous context. The implementation is very efficient, owing to the "static pointer" style of coding already used. The "wake" function just calls ALooper_wake, and cloning/dropping the waker is just a copy. Signed-off-by: John Nunley --- .gitignore | 1 + android-activity/src/game_activity/mod.rs | 22 +++++++++++++++++++++ android-activity/src/native_activity/mod.rs | 22 +++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/.gitignore b/.gitignore index eb5a316..a9d37c5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ target +Cargo.lock diff --git a/android-activity/src/game_activity/mod.rs b/android-activity/src/game_activity/mod.rs index 7cf3894..333de52 100644 --- a/android-activity/src/game_activity/mod.rs +++ b/android-activity/src/game_activity/mod.rs @@ -8,6 +8,7 @@ use std::ptr; use std::ptr::NonNull; use std::sync::Weak; use std::sync::{Arc, Mutex, RwLock}; +use std::task::{RawWaker, RawWakerVTable, Waker}; use std::time::Duration; use libc::c_void; @@ -118,6 +119,27 @@ impl AndroidAppWaker { ALooper_wake(self.looper.as_ptr()); } } + + /// Creates a [`Waker`] that wakes up the [`AndroidApp`]. + /// + /// This is useful for using this crate in `async` environments. + /// + /// [`Waker`]: std::task::Waker + pub fn waker(self) -> Waker { + const VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake, drop); + + unsafe fn clone(data: *const ()) -> RawWaker { + RawWaker::new(data, &VTABLE) + } + + unsafe fn wake(data: *const ()) { + ndk_sys::ALooper_wake(data as *const _ as *mut _) + } + + unsafe fn drop(_: *const ()) {} + + unsafe { Waker::from_raw(RawWaker::new(self.looper.as_ptr() as *const (), &VTABLE)) } + } } impl AndroidApp { diff --git a/android-activity/src/native_activity/mod.rs b/android-activity/src/native_activity/mod.rs index 2adcd52..d6e0b2b 100644 --- a/android-activity/src/native_activity/mod.rs +++ b/android-activity/src/native_activity/mod.rs @@ -6,6 +6,7 @@ use std::panic::AssertUnwindSafe; use std::ptr; use std::ptr::NonNull; use std::sync::{Arc, Mutex, RwLock, Weak}; +use std::task::{RawWaker, RawWakerVTable, Waker}; use std::time::Duration; use libc::c_void; @@ -83,6 +84,27 @@ impl AndroidAppWaker { ndk_sys::ALooper_wake(self.looper.as_ptr()); } } + + /// Creates a [`Waker`] that wakes up the [`AndroidApp`]. + /// + /// This is useful for using this crate in `async` environments. + /// + /// [`Waker`]: std::task::Waker + pub fn waker(self) -> Waker { + const VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake, drop); + + unsafe fn clone(data: *const ()) -> RawWaker { + RawWaker::new(data, &VTABLE) + } + + unsafe fn wake(data: *const ()) { + ndk_sys::ALooper_wake(data as *const _ as *mut _) + } + + unsafe fn drop(_: *const ()) {} + + unsafe { Waker::from_raw(RawWaker::new(self.looper.as_ptr() as *const (), &VTABLE)) } + } } impl AndroidApp {