From 01ff08692f653ea5d072736f8ab2844cf656ab5d Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Tue, 6 Dec 2022 19:21:30 +0000 Subject: [PATCH] Removes ndk-glue + ndk-macro as part of #372 modularization The ndk-glue and ndk-macro subdirectores have been split into a stand-alone repository at: https://github.com/rust-mobile/ndk-glue This is being done as part of the modularization effort described in issue #372 The stand-alone repository was filtered like this: ``` git clone https://github.com/newren/git-filter-repo git clone https://github.com/rust-windowing/android-ndk-rs.git ndk-glue cd ndk-glue py ../git-filter-repo/git-filter-repo \ --path ndk-glue --path ndk-macro \ --path ndk-examples --path-rename ndk-examples:examples \ --path LICENSE-APACHE --path LICENSE-MIT \ --path Cargo.toml --path rustfmt.toml \ --path .github --path .gitignore ``` The last commit in this repo that is included within the stand-alone repository is 107f03e3858bdced3a7a898e43b339b73d7fc1af Although ndk-glue is also being deprecated at the same time as splitting it out this commit doesn't make any README changes for this repo yet which will be addressed separately. --- Cargo.toml | 2 - ndk-glue/CHANGELOG.md | 76 ------ ndk-glue/Cargo.toml | 38 --- ndk-glue/README.md | 6 - ndk-glue/src/lib.rs | 431 ---------------------------------- ndk-macro/CHANGELOG.md | 15 -- ndk-macro/Cargo.toml | 30 --- ndk-macro/README.md | 22 -- ndk-macro/src/expand.rs | 503 ---------------------------------------- ndk-macro/src/helper.rs | 66 ------ ndk-macro/src/lib.rs | 24 -- ndk-macro/src/parse.rs | 197 ---------------- 12 files changed, 1410 deletions(-) delete mode 100644 ndk-glue/CHANGELOG.md delete mode 100644 ndk-glue/Cargo.toml delete mode 100644 ndk-glue/README.md delete mode 100644 ndk-glue/src/lib.rs delete mode 100644 ndk-macro/CHANGELOG.md delete mode 100644 ndk-macro/Cargo.toml delete mode 100644 ndk-macro/README.md delete mode 100644 ndk-macro/src/expand.rs delete mode 100644 ndk-macro/src/helper.rs delete mode 100644 ndk-macro/src/lib.rs delete mode 100644 ndk-macro/src/parse.rs diff --git a/Cargo.toml b/Cargo.toml index b189f3e0..2ec7520a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,10 +2,8 @@ members = [ "ndk", "ndk-context", - "ndk-macro", "ndk-build", "ndk-examples", - "ndk-glue", "ndk-sys", "cargo-apk", ] diff --git a/ndk-glue/CHANGELOG.md b/ndk-glue/CHANGELOG.md deleted file mode 100644 index f4c96e06..00000000 --- a/ndk-glue/CHANGELOG.md +++ /dev/null @@ -1,76 +0,0 @@ -# Unreleased - -- **Breaking:** `NativeActivity` is now behind a lock, and will be removed as soon as `onDestroy` - is called. Due to the async nature of events, make sure to hold on to the lock received from - `native_activity()` _beforehand_ if you wish to use it during handling of `Event::Destroy`. The - lock should be released to allow `onDestroy` to return. - -# 0.7.0 (2022-07-24) - -- **Breaking:** Provide a `LockReadGuard` newtype around `NativeWindow`/`InputQueue` to hide the underlying lock implementation. (#288) -- **Breaking:** Transpose `LockReadGuard>` into `Option>` to only necessitate an `Option` unpack/`unwrap()` once. (#282) - -# 0.6.2 (2022-04-19) - -- Call `ndk_context::release_android_context()` function to remove `AndroidContext` when activity is destroyed. (#263) - -# 0.6.1 (2022-02-14) - -- Initialize `ndk-context` for cross-version access to the Java `VM` and Android `Context`. - -# 0.6.0 (2022-01-05) - -- **Breaking:** Update to `ndk-sys 0.3.0` and `ndk 0.6.0`. (#214) - -# 0.5.2 (2022-04-19) - -- Call `ndk_context::release_android_context()` function to remove `AndroidContext` when activity is destroyed. (#263) - -# 0.5.1 (2022-02-15) - -- Initialize `ndk-context` for cross-version access to the Java `VM` and Android `Context`. - -# 0.5.0 (2021-11-22) - -- Document when to lock and unlock the window/input queue when certain events are received. -- **Breaking:** Update to `ndk 0.5.0` and `ndk-macros 0.3.0`. - -# 0.4.2 (2022-04-19) - -- Call `ndk_context::release_android_context()` function to remove `AndroidContext` when activity is destroyed. (#263) - -# 0.4.1 (2022-02-15) - -- Initialize `ndk-context` for cross-version access to the Java `VM` and Android `Context`. - -# 0.4.0 (2021-08-02) - -- Looper is now created before returning from `ANativeActivity_onCreate`, solving - race conditions in `onInputQueueCreated`. -- Event pipe and looper are now notified of removal _before_ destroying `NativeWindow` - and `InputQueue`. This allows applications to unlock their read-locks of these instances - first (which they are supposed to hold on to during use) instead of deadlocking in - Android callbacks. -- Reexport `android_logger` and `log` from the crate root for `ndk-macro` to use. -- Use new `FdEvents` `bitflags` for looper file descriptor events. -- Update to `ndk` 0.4.0. - This minor dependency bump causes a minor bump for `ndk-glue` too. - -# 0.3.0 (2021-01-30) - -- **Breaking:** Looper `ident` not passed in `data` pointer anymore. - If you are relying on `Poll::Event::data` to tell event fd and - input queue apart, please use `Poll::Event::ident` and the new - constants introduced in `ndk-glue`! - -# 0.2.1 (2020-10-15) - -- Fix documentation build on docs.rs - -# 0.2.0 (2020-09-15) - -- **Breaking:** Removed `ndk_glue` macro in favor of new `main` attribute macro. - -# 0.1.0 (2020-04-22) - -- Initial release! 🎉 diff --git a/ndk-glue/Cargo.toml b/ndk-glue/Cargo.toml deleted file mode 100644 index beb91894..00000000 --- a/ndk-glue/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -[package] -name = "ndk-glue" -version = "0.7.0" -authors = ["The Rust Windowing contributors"] -edition = "2018" -description = "Startup code for android binaries" -license = "MIT OR Apache-2.0" -keywords = ["android", "ndk"] -readme = "README.md" -documentation = "https://docs.rs/ndk-glue" -homepage = "https://github.com/rust-windowing/android-ndk-rs" -repository = "https://github.com/rust-windowing/android-ndk-rs" -rust-version = "1.60" - -[dependencies] -android_logger = { version = "0.11", optional = true } -libc = "0.2.84" -log = "0.4.14" -ndk = { path = "../ndk", version = "0.7.0" } -ndk-context = { path = "../ndk-context", version = "0.1.1" } -ndk-macro = { path = "../ndk-macro", version = "0.3.0" } -ndk-sys = { path = "../ndk-sys", version = "0.4.0" } -once_cell = "1" -parking_lot = "0.12" - -[features] -default = [] -test = ["ndk/test", "ndk-sys/test"] -logger = ["android_logger", "ndk-macro/logger"] - -[package.metadata.docs.rs] -rustdoc-args = ["--cfg", "docsrs"] -targets = [ - "aarch64-linux-android", - "armv7-linux-androideabi", - "i686-linux-android", - "x86_64-linux-android", -] diff --git a/ndk-glue/README.md b/ndk-glue/README.md deleted file mode 100644 index c434770e..00000000 --- a/ndk-glue/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# ndk-glue - -Interoperability library for a native Rust application with the Android framework. -Provides access to `NativeActivity`, `NativeWindow` and `InputQueue`. - -This library exports the `main` attribute macro from `ndk-macro`, see the corresponding README for more details. diff --git a/ndk-glue/src/lib.rs b/ndk-glue/src/lib.rs deleted file mode 100644 index 60a0d6ff..00000000 --- a/ndk-glue/src/lib.rs +++ /dev/null @@ -1,431 +0,0 @@ -#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] - -use log::Level; -use ndk::input_queue::InputQueue; -use ndk::looper::{FdEvent, ForeignLooper, ThreadLooper}; -use ndk::native_activity::NativeActivity; -use ndk::native_window::NativeWindow; -use ndk_sys::{AInputQueue, ANativeActivity, ANativeWindow, ARect}; -use once_cell::sync::Lazy; -use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard}; -use std::ffi::{CStr, CString}; -use std::fmt; -use std::fs::File; -use std::io::{BufRead, BufReader}; -use std::ops::Deref; -use std::os::raw; -use std::os::unix::prelude::*; -use std::ptr::NonNull; -use std::sync::{Arc, Condvar, Mutex}; -use std::thread; - -#[cfg(feature = "logger")] -pub use android_logger; -#[cfg(feature = "logger")] -pub use log; - -pub use ndk_macro::main; - -/// `ndk-glue` macros register the reading end of an event pipe with the -/// main [`ThreadLooper`] under this `ident`. -/// When returned from [`ThreadLooper::poll_*`][ThreadLooper::poll_once] -/// an event can be retrieved from [`poll_events()`]. -pub const NDK_GLUE_LOOPER_EVENT_PIPE_IDENT: i32 = 0; - -/// The [`InputQueue`] received from Android is registered with the main -/// [`ThreadLooper`] under this `ident`. -/// When returned from [`ThreadLooper::poll_*`][ThreadLooper::poll_once] -/// an event can be retrieved from [`input_queue()`]. -pub const NDK_GLUE_LOOPER_INPUT_QUEUE_IDENT: i32 = 1; - -pub fn android_log(level: Level, tag: &CStr, msg: &CStr) { - let prio = match level { - Level::Error => ndk_sys::android_LogPriority::ANDROID_LOG_ERROR, - Level::Warn => ndk_sys::android_LogPriority::ANDROID_LOG_WARN, - Level::Info => ndk_sys::android_LogPriority::ANDROID_LOG_INFO, - Level::Debug => ndk_sys::android_LogPriority::ANDROID_LOG_DEBUG, - Level::Trace => ndk_sys::android_LogPriority::ANDROID_LOG_VERBOSE, - }; - unsafe { - ndk_sys::__android_log_write(prio.0 as raw::c_int, tag.as_ptr(), msg.as_ptr()); - } -} - -static NATIVE_ACTIVITY: Lazy>> = Lazy::new(Default::default); -static NATIVE_WINDOW: Lazy>> = Lazy::new(Default::default); -static INPUT_QUEUE: Lazy>> = Lazy::new(Default::default); -static CONTENT_RECT: Lazy> = Lazy::new(Default::default); -static LOOPER: Lazy>> = Lazy::new(Default::default); - -/// This function accesses a `static` variable internally and must only be used if you are sure -/// there is exactly one version of [`ndk_glue`][crate] in your dependency tree. -/// -/// If you need access to the `JavaVM` through [`NativeActivity::vm()`] or Activity `Context` -/// through [`NativeActivity::activity()`], please use the [`ndk_context`] crate and its -/// [`ndk_context::android_context()`] getter to acquire the `JavaVM` and `Context` instead. -pub fn native_activity() -> Option> { - LockReadGuard::from_wrapped_option(NATIVE_ACTIVITY.read()) -} - -pub struct LockReadGuard(MappedRwLockReadGuard<'static, T>); - -impl LockReadGuard { - /// Transpose an [`Option`] wrapped inside a [`LockReadGuard`] - /// - /// This is a _read_ lock for which the contents can't change; hence allowing the user to only - /// check for [`None`] once and hold a lock containing `T` directly thereafter, without - /// subsequent infallible [`Option::unwrap()`]s. - fn from_wrapped_option(wrapped: RwLockReadGuard<'static, Option>) -> Option { - RwLockReadGuard::try_map(wrapped, Option::as_ref) - .ok() - .map(Self) - } -} - -impl Deref for LockReadGuard { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl fmt::Debug for LockReadGuard { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -impl fmt::Display for LockReadGuard { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -/// Returns a [`NativeWindow`] held inside a lock, preventing Android from freeing it immediately -/// in [its `NativeWindow` destructor]. -/// -/// If the window is in use by e.g. a graphics API, make sure to hold on to this lock. -/// -/// After receiving [`Event::WindowDestroyed`] `ndk-glue` will block in Android's [`NativeWindow`] destructor -/// callback until the lock is released, returning to Android and allowing it to free the window. -/// -/// [its `NativeWindow` destructor]: https://developer.android.com/ndk/reference/struct/a-native-activity-callbacks#onnativewindowdestroyed -/// -/// # Warning -/// This function accesses a `static` variable internally and must only be used if you are sure -/// there is exactly one version of `ndk_glue` in your dependency tree. -pub fn native_window() -> Option> { - LockReadGuard::from_wrapped_option(NATIVE_WINDOW.read()) -} - -/// Returns an [`InputQueue`] held inside a lock, preventing Android from freeing it immediately -/// in [its `InputQueue` destructor]. -/// -/// After receiving [`Event::InputQueueDestroyed`] `ndk-glue` will block in Android's [`InputQueue`] destructor -/// callback until the lock is released, returning to Android and allowing it to free the window. -/// -/// [its `InputQueue` destructor]: https://developer.android.com/ndk/reference/struct/a-native-activity-callbacks#oninputqueuedestroyed -/// -/// # Warning -/// This function accesses a `static` variable internally and must only be used if you are sure -/// there is exactly one version of `ndk_glue` in your dependency tree. -pub fn input_queue() -> Option> { - LockReadGuard::from_wrapped_option(INPUT_QUEUE.read()) -} - -/// This function accesses a `static` variable internally and must only be used if you are sure -/// there is exactly one version of `ndk_glue` in your dependency tree. -pub fn content_rect() -> Rect { - CONTENT_RECT.read().clone() -} - -static PIPE: Lazy<[RawFd; 2]> = Lazy::new(|| { - let mut pipe: [RawFd; 2] = Default::default(); - unsafe { libc::pipe(pipe.as_mut_ptr()) }; - pipe -}); - -pub fn poll_events() -> Option { - unsafe { - let size = std::mem::size_of::(); - let mut event = Event::Start; - if libc::read(PIPE[0], &mut event as *mut _ as *mut _, size) == size as _ { - Some(event) - } else { - None - } - } -} - -unsafe fn wake(_activity: *mut ANativeActivity, event: Event) { - log::trace!("{:?}", event); - let size = std::mem::size_of::(); - let res = libc::write(PIPE[1], &event as *const _ as *const _, size); - assert_eq!(res, size as _); -} - -#[derive(Clone, Debug, Default, Eq, PartialEq)] -pub struct Rect { - pub left: u32, - pub top: u32, - pub right: u32, - pub bottom: u32, -} - -#[derive(Clone, Debug, Eq, PartialEq)] -#[repr(u8)] -pub enum Event { - Start, - Resume, - SaveInstanceState, - Pause, - Stop, - /// The native activity will be stopped and destroyed after this event. - /// Due to the async nature of these events, make sure to hold on to the - /// lock received from [`native_activity()`] _beforehand_ if you wish to use - /// it during handling of [`Event::Destroy`]. The lock should be released to - /// allow `onDestroy` to return. - Destroy, - ConfigChanged, - LowMemory, - WindowLostFocus, - WindowHasFocus, - /// A [`NativeWindow`] is now available through [`native_window()`]. See that function for more - /// details about holding on to the returned [`LockReadGuard`]. - /// - /// Be sure to release any resources (e.g. Vulkan/OpenGL graphics surfaces) created from - /// it followed by releasing this lock upon receiving [`Event::WindowDestroyed`]. - WindowCreated, - WindowResized, - WindowRedrawNeeded, - /// If the window is in use by e.g. a graphics API, make sure the [`LockReadGuard`] from - /// [`native_window()`] is held on to until after freeing those resources. - /// - /// After receiving this [`Event`] `ndk_glue` will block inside its [`NativeWindow`] destructor - /// until that read-lock is released before returning to Android and allowing it to free the - /// window. - /// - /// From this point [`native_window()`] will return [`None`] until receiving - /// [`Event::WindowCreated`] again. - WindowDestroyed, - /// An [`InputQueue`] is now available through [`input_queue()`]. - /// - /// Be sure to release the returned lock upon receiving [`Event::InputQueueDestroyed`]. - InputQueueCreated, - /// After receiving this [`Event`] `ndk_glue` will block inside its [`InputQueue`] destructor - /// until the read-lock from [`input_queue()`] is released before returning to Android and - /// allowing it to free the input queue. - /// - /// From this point [`input_queue()`] will return [`None`] until receiving - /// [`Event::InputQueueCreated`] again. - InputQueueDestroyed, - ContentRectChanged, -} - -/// # Safety -/// `activity` must either be null (resulting in a safe panic) -/// or a pointer to a valid Android `ANativeActivity`. -pub unsafe fn init( - activity: *mut ANativeActivity, - _saved_state: *mut u8, - _saved_state_size: usize, - main: fn(), -) { - let mut activity = NonNull::new(activity).unwrap(); - let mut callbacks = activity.as_mut().callbacks.as_mut().unwrap(); - callbacks.onStart = Some(on_start); - callbacks.onResume = Some(on_resume); - callbacks.onSaveInstanceState = Some(on_save_instance_state); - callbacks.onPause = Some(on_pause); - callbacks.onStop = Some(on_stop); - callbacks.onDestroy = Some(on_destroy); - callbacks.onWindowFocusChanged = Some(on_window_focus_changed); - callbacks.onNativeWindowCreated = Some(on_window_created); - callbacks.onNativeWindowResized = Some(on_window_resized); - callbacks.onNativeWindowRedrawNeeded = Some(on_window_redraw_needed); - callbacks.onNativeWindowDestroyed = Some(on_window_destroyed); - callbacks.onInputQueueCreated = Some(on_input_queue_created); - callbacks.onInputQueueDestroyed = Some(on_input_queue_destroyed); - callbacks.onContentRectChanged = Some(on_content_rect_changed); - callbacks.onConfigurationChanged = Some(on_configuration_changed); - callbacks.onLowMemory = Some(on_low_memory); - - let activity = NativeActivity::from_ptr(activity); - ndk_context::initialize_android_context(activity.vm().cast(), activity.activity().cast()); - NATIVE_ACTIVITY.write().replace(activity); - - let mut logpipe: [RawFd; 2] = Default::default(); - libc::pipe(logpipe.as_mut_ptr()); - libc::dup2(logpipe[1], libc::STDOUT_FILENO); - libc::dup2(logpipe[1], libc::STDERR_FILENO); - thread::spawn(move || { - let tag = CStr::from_bytes_with_nul(b"RustStdoutStderr\0").unwrap(); - let file = File::from_raw_fd(logpipe[0]); - let mut reader = BufReader::new(file); - let mut buffer = String::new(); - loop { - buffer.clear(); - if let Ok(len) = reader.read_line(&mut buffer) { - if len == 0 { - break; - } else if let Ok(msg) = CString::new(buffer.clone()) { - android_log(Level::Info, tag, &msg); - } - } - } - }); - - let looper_ready = Arc::new(Condvar::new()); - let signal_looper_ready = looper_ready.clone(); - - thread::spawn(move || { - let looper = ThreadLooper::prepare(); - let foreign = looper.into_foreign(); - foreign - .add_fd( - PIPE[0], - NDK_GLUE_LOOPER_EVENT_PIPE_IDENT, - FdEvent::INPUT, - std::ptr::null_mut(), - ) - .unwrap(); - - { - let mut locked_looper = LOOPER.lock().unwrap(); - locked_looper.replace(foreign); - signal_looper_ready.notify_one(); - } - - main() - }); - - // Don't return from this function (`ANativeActivity_onCreate`) until the thread - // has created its `ThreadLooper` and assigned it to the static `LOOPER` - // variable. It will be used from `on_input_queue_created` as soon as this - // function returns. - let locked_looper = LOOPER.lock().unwrap(); - let _mutex_guard = looper_ready - .wait_while(locked_looper, |looper| looper.is_none()) - .unwrap(); -} - -unsafe extern "C" fn on_start(activity: *mut ANativeActivity) { - wake(activity, Event::Start); -} - -unsafe extern "C" fn on_resume(activity: *mut ANativeActivity) { - wake(activity, Event::Resume); -} - -unsafe extern "C" fn on_save_instance_state( - activity: *mut ANativeActivity, - _out_size: *mut ndk_sys::size_t, -) -> *mut raw::c_void { - // TODO - wake(activity, Event::SaveInstanceState); - std::ptr::null_mut() -} - -unsafe extern "C" fn on_pause(activity: *mut ANativeActivity) { - wake(activity, Event::Pause); -} - -unsafe extern "C" fn on_stop(activity: *mut ANativeActivity) { - wake(activity, Event::Stop); -} - -unsafe extern "C" fn on_destroy(activity: *mut ANativeActivity) { - wake(activity, Event::Destroy); - ndk_context::release_android_context(); - let mut native_activity_guard = NATIVE_ACTIVITY.write(); - let native_activity = native_activity_guard.take().unwrap(); - assert_eq!(native_activity.ptr().as_ptr(), activity); -} - -unsafe extern "C" fn on_configuration_changed(activity: *mut ANativeActivity) { - wake(activity, Event::ConfigChanged); -} - -unsafe extern "C" fn on_low_memory(activity: *mut ANativeActivity) { - wake(activity, Event::LowMemory); -} - -unsafe extern "C" fn on_window_focus_changed( - activity: *mut ANativeActivity, - has_focus: raw::c_int, -) { - let event = if has_focus == 0 { - Event::WindowLostFocus - } else { - Event::WindowHasFocus - }; - wake(activity, event); -} - -unsafe extern "C" fn on_window_created(activity: *mut ANativeActivity, window: *mut ANativeWindow) { - NATIVE_WINDOW - .write() - .replace(NativeWindow::clone_from_ptr(NonNull::new(window).unwrap())); - wake(activity, Event::WindowCreated); -} - -unsafe extern "C" fn on_window_resized( - activity: *mut ANativeActivity, - _window: *mut ANativeWindow, -) { - wake(activity, Event::WindowResized); -} - -unsafe extern "C" fn on_window_redraw_needed( - activity: *mut ANativeActivity, - _window: *mut ANativeWindow, -) { - wake(activity, Event::WindowRedrawNeeded); -} - -unsafe extern "C" fn on_window_destroyed( - activity: *mut ANativeActivity, - window: *mut ANativeWindow, -) { - wake(activity, Event::WindowDestroyed); - let mut native_window_guard = NATIVE_WINDOW.write(); - assert_eq!(native_window_guard.as_ref().unwrap().ptr().as_ptr(), window); - native_window_guard.take(); -} - -unsafe extern "C" fn on_input_queue_created( - activity: *mut ANativeActivity, - queue: *mut AInputQueue, -) { - let input_queue = InputQueue::from_ptr(NonNull::new(queue).unwrap()); - let locked_looper = LOOPER.lock().unwrap(); - // The looper should always be `Some` after `fn init()` returns, unless - // future code cleans it up and sets it back to `None` again. - let looper = locked_looper.as_ref().expect("Looper does not exist"); - input_queue.attach_looper(looper, NDK_GLUE_LOOPER_INPUT_QUEUE_IDENT); - INPUT_QUEUE.write().replace(input_queue); - wake(activity, Event::InputQueueCreated); -} - -unsafe extern "C" fn on_input_queue_destroyed( - activity: *mut ANativeActivity, - queue: *mut AInputQueue, -) { - wake(activity, Event::InputQueueDestroyed); - let mut input_queue_guard = INPUT_QUEUE.write(); - let input_queue = input_queue_guard.take().unwrap(); - assert_eq!(input_queue.ptr().as_ptr(), queue); - input_queue.detach_looper(); -} - -unsafe extern "C" fn on_content_rect_changed(activity: *mut ANativeActivity, rect: *const ARect) { - let rect = Rect { - left: (*rect).left as _, - top: (*rect).top as _, - right: (*rect).right as _, - bottom: (*rect).bottom as _, - }; - *CONTENT_RECT.write() = rect; - wake(activity, Event::ContentRectChanged); -} diff --git a/ndk-macro/CHANGELOG.md b/ndk-macro/CHANGELOG.md deleted file mode 100644 index d4521b36..00000000 --- a/ndk-macro/CHANGELOG.md +++ /dev/null @@ -1,15 +0,0 @@ -# Unreleased - -# 0.3.0 (2021-11-22) - -- **Breaking:** Removed `android_logger` and `log` crate path overrides from macro input attributes in favour of using the reexports from `ndk-glue`. - Applications no longer have to provide these crates in scope of the `ndk_glue::main` macro when logging is enabled. - -# 0.2.0 (2020-09-15) - -- Added crate name override option -- **Breaking:** Changed macro attribute syntax - -# 0.1.0 (2020-07-29) - -- Initial release! 🎉 diff --git a/ndk-macro/Cargo.toml b/ndk-macro/Cargo.toml deleted file mode 100644 index af0cc8db..00000000 --- a/ndk-macro/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "ndk-macro" -version = "0.3.0" -authors = ["The Rust Windowing contributors"] -edition = "2018" -description = "Helper macros for android ndk" -license = "MIT OR Apache-2.0" -keywords = ["android", "ndk"] -readme = "README.md" -documentation = "https://docs.rs/ndk-macro" -homepage = "https://github.com/rust-windowing/android-ndk-rs" -repository = "https://github.com/rust-windowing/android-ndk-rs" -rust-version = "1.60" - -[lib] -proc-macro = true - -[dependencies] -proc-macro2 = "1.0.24" -proc-macro-crate = "1.0" -quote = "1.0.8" -syn = { version = "1.0.60", features = ["full"] } -darling = "0.14" - -[features] -default = [] -logger = [] - -[package.metadata.docs.rs] -rustdoc-args = ["--cfg", "docsrs"] diff --git a/ndk-macro/README.md b/ndk-macro/README.md deleted file mode 100644 index d09671f3..00000000 --- a/ndk-macro/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# ndk-macro - -Implementation of the attribute procedural macro `main` which applied directly to main function. - -This macro is re-exported in `ndk-glue`. Typically, it's not needed to depend on this library directly! - -## Usage -```Rust -#[cfg_attr(target_os = "android", ndk_glue::main(backtrace = "on"))] -pub fn main() { - println!("hello world"); -} -``` - -The attribute macro supports optional input attributes: - -- `backtrace = "on|full"`: Enables backtraces by setting the `RUST_BACKTRACE` env var -- `ndk_glue = "path::to::ndk_glue"`: Overrides default path to __ndk_glue__ crate -- `logger(...props)`: Configures android logger with the passed configuration (requires the `logger` feature): - - `level = "error|warn|info|debug|trace"`: Changes log level for logger - - `tag = "my-tag"`: Assigns tag to logger - - `filter = "filtering-rules"`: Changes default filtering rules diff --git a/ndk-macro/src/expand.rs b/ndk-macro/src/expand.rs deleted file mode 100644 index 28df80ce..00000000 --- a/ndk-macro/src/expand.rs +++ /dev/null @@ -1,503 +0,0 @@ -use core::iter::once; -use proc_macro2::TokenStream; -use quote::{quote, ToTokens}; -use syn::ItemFn; - -use crate::{ - helper::crate_path, - parse::{BacktraceProp, MainAttr}, -}; - -impl ToTokens for BacktraceProp { - fn to_tokens(&self, tokens: &mut TokenStream) { - use BacktraceProp::*; - - let prop = match self { - On => Some(quote! { "1" }), - Full => Some(quote! { "full" }), - }; - - tokens.extend(quote! { - std::env::set_var("RUST_BACKTRACE", #prop); - }); - } -} - -#[cfg(feature = "logger")] -mod logger { - use super::*; - use crate::parse::{LogLevel, LoggerProp}; - use syn::Path; - - impl LoggerProp { - pub(crate) fn expand(&self, glue_crate: &Path) -> TokenStream { - let mut withs = Vec::new(); - - if let Some(tag) = &self.tag { - withs.push(quote! { with_tag(#tag) }); - } - if let Some(level) = &self.level { - withs.push(quote! { with_min_level(#glue_crate::log::Level::#level) }); - } - if let Some(filter) = &self.filter { - withs.push(quote! { - with_filter(#glue_crate::android_logger::FilterBuilder::new().parse(#filter).build()) - }); - } - - quote! { - #glue_crate::android_logger::init_once( - #glue_crate::android_logger::Config::default() - #(.#withs)* - ); - } - } - } - - impl ToTokens for LogLevel { - fn to_tokens(&self, tokens: &mut TokenStream) { - use LogLevel::*; - - tokens.extend(match self { - Error => quote! { Error }, - Warn => quote! { Warn }, - Info => quote! { Info }, - Debug => quote! { Debug }, - Trace => quote! { Trace }, - }); - } - } -} - -impl MainAttr { - pub fn expand(&self, main_fn_item: &ItemFn) -> TokenStream { - let main_fn_name = &main_fn_item.sig.ident; - let glue_crate = crate_path("ndk-glue", &self.ndk_glue); - - let preamble = { - let backtrace = &self.backtrace; - once(quote! { #backtrace }) - }; - - #[cfg(feature = "logger")] - let preamble = preamble.chain( - self.logger - .as_ref() - .map(|l| l.expand(&glue_crate)) - .into_iter(), - ); - - quote! { - #[no_mangle] - unsafe extern "C" fn ANativeActivity_onCreate( - activity: *mut std::os::raw::c_void, - saved_state: *mut std::os::raw::c_void, - saved_state_size: usize, - ) { - #(#preamble)* - #glue_crate::init( - activity as _, - saved_state as _, - saved_state_size as _, - #main_fn_name, - ); - } - - #main_fn_item - } - } -} - -#[cfg(test)] -mod test { - use crate::parse::{BacktraceProp, MainAttr}; - use quote::quote; - use syn::parse_quote; - - #[test] - fn main_without_props() { - let attr = MainAttr::default(); - let item = parse_quote! { fn main() {} }; - let actual = attr.expand(&item); - let expected = quote! { - #[no_mangle] - unsafe extern "C" fn ANativeActivity_onCreate( - activity: *mut std::os::raw::c_void, - saved_state: *mut std::os::raw::c_void, - saved_state_size: usize, - ) { - ndk_glue::init( - activity as _, - saved_state as _, - saved_state_size as _, - main, - ); - } - fn main() {} - }; - assert_eq!(actual.to_string(), expected.to_string()); - } - - #[test] - fn main_with_backtrace_on() { - let attr = MainAttr { - backtrace: Some(BacktraceProp::On), - ..Default::default() - }; - let item = parse_quote! { fn main() {} }; - let actual = attr.expand(&item); - let expected = quote! { - #[no_mangle] - unsafe extern "C" fn ANativeActivity_onCreate( - activity: *mut std::os::raw::c_void, - saved_state: *mut std::os::raw::c_void, - saved_state_size: usize, - ) { - std::env::set_var("RUST_BACKTRACE", "1"); - ndk_glue::init( - activity as _, - saved_state as _, - saved_state_size as _, - main, - ); - } - fn main() {} - }; - assert_eq!(actual.to_string(), expected.to_string()); - } - - #[test] - fn main_with_backtrace_full() { - let attr = MainAttr { - backtrace: Some(BacktraceProp::Full), - ..Default::default() - }; - let item = parse_quote! { fn main() {} }; - let actual = attr.expand(&item); - let expected = quote! { - #[no_mangle] - unsafe extern "C" fn ANativeActivity_onCreate( - activity: *mut std::os::raw::c_void, - saved_state: *mut std::os::raw::c_void, - saved_state_size: usize, - ) { - std::env::set_var("RUST_BACKTRACE", "full"); - ndk_glue::init( - activity as _, - saved_state as _, - saved_state_size as _, - main, - ); - } - fn main() {} - }; - assert_eq!(actual.to_string(), expected.to_string()); - } - - #[test] - fn main_with_overridden_ndk_glue() { - let attr = MainAttr { - ndk_glue: Some(parse_quote! { my::re::exported::ndk_glue }), - ..Default::default() - }; - let item = parse_quote! { fn main() {} }; - let actual = attr.expand(&item); - let expected = quote! { - #[no_mangle] - unsafe extern "C" fn ANativeActivity_onCreate( - activity: *mut std::os::raw::c_void, - saved_state: *mut std::os::raw::c_void, - saved_state_size: usize, - ) { - my::re::exported::ndk_glue::init( - activity as _, - saved_state as _, - saved_state_size as _, - main, - ); - } - fn main() {} - }; - assert_eq!(actual.to_string(), expected.to_string()); - } - - #[cfg(feature = "logger")] - mod logger { - use super::*; - use crate::parse::{LogLevel, LoggerProp}; - - #[test] - fn main_with_logger_default() { - let attr = MainAttr { - logger: Some(LoggerProp::default()), - ..Default::default() - }; - let item = parse_quote! { fn main() {} }; - let actual = attr.expand(&item); - let expected = quote! { - #[no_mangle] - unsafe extern "C" fn ANativeActivity_onCreate( - activity: *mut std::os::raw::c_void, - saved_state: *mut std::os::raw::c_void, - saved_state_size: usize, - ) { - ndk_glue::android_logger::init_once( - ndk_glue::android_logger::Config::default() - ); - ndk_glue::init( - activity as _, - saved_state as _, - saved_state_size as _, - main, - ); - } - fn main() {} - }; - assert_eq!(actual.to_string(), expected.to_string()); - } - - #[test] - fn main_with_logger_with_min_level() { - let attr = MainAttr { - logger: Some(LoggerProp { - level: Some(LogLevel::Debug), - ..Default::default() - }), - ..Default::default() - }; - let item = parse_quote! { fn main() {} }; - let actual = attr.expand(&item); - let expected = quote! { - #[no_mangle] - unsafe extern "C" fn ANativeActivity_onCreate( - activity: *mut std::os::raw::c_void, - saved_state: *mut std::os::raw::c_void, - saved_state_size: usize, - ) { - ndk_glue::android_logger::init_once( - ndk_glue::android_logger::Config::default() - .with_min_level(ndk_glue::log::Level::Debug) - ); - ndk_glue::init( - activity as _, - saved_state as _, - saved_state_size as _, - main, - ); - } - fn main() {} - }; - assert_eq!(actual.to_string(), expected.to_string()); - } - - #[test] - fn main_with_logger_with_tag() { - let attr = MainAttr { - logger: Some(LoggerProp { - tag: Some("my-tag".into()), - ..Default::default() - }), - ..Default::default() - }; - let item = parse_quote! { fn my_main() {} }; - let actual = attr.expand(&item); - let expected = quote! { - #[no_mangle] - unsafe extern "C" fn ANativeActivity_onCreate( - activity: *mut std::os::raw::c_void, - saved_state: *mut std::os::raw::c_void, - saved_state_size: usize, - ) { - ndk_glue::android_logger::init_once( - ndk_glue::android_logger::Config::default() - .with_tag("my-tag") - ); - ndk_glue::init( - activity as _, - saved_state as _, - saved_state_size as _, - my_main, - ); - } - fn my_main() {} - }; - assert_eq!(actual.to_string(), expected.to_string()); - } - - #[test] - fn main_with_logger_with_filter() { - let attr = MainAttr { - logger: Some(LoggerProp { - filter: Some("debug,hellow::world=trace".into()), - ..Default::default() - }), - ..Default::default() - }; - let item = parse_quote! { fn my_main() {} }; - let actual = attr.expand(&item); - let expected = quote! { - #[no_mangle] - unsafe extern "C" fn ANativeActivity_onCreate( - activity: *mut std::os::raw::c_void, - saved_state: *mut std::os::raw::c_void, - saved_state_size: usize, - ) { - ndk_glue::android_logger::init_once( - ndk_glue::android_logger::Config::default() - .with_filter(ndk_glue::android_logger::FilterBuilder::new().parse("debug,hellow::world=trace").build()) - ); - ndk_glue::init( - activity as _, - saved_state as _, - saved_state_size as _, - my_main, - ); - } - fn my_main() {} - }; - assert_eq!(actual.to_string(), expected.to_string()); - } - - #[test] - fn main_with_logger_with_min_level_and_with_tag() { - let attr = MainAttr { - logger: Some(LoggerProp { - level: Some(LogLevel::Warn), - tag: Some("my-tag".into()), - ..Default::default() - }), - ..Default::default() - }; - let item = parse_quote! { fn my_main() {} }; - let actual = attr.expand(&item); - let expected = quote! { - #[no_mangle] - unsafe extern "C" fn ANativeActivity_onCreate( - activity: *mut std::os::raw::c_void, - saved_state: *mut std::os::raw::c_void, - saved_state_size: usize, - ) { - ndk_glue::android_logger::init_once( - ndk_glue::android_logger::Config::default() - .with_tag("my-tag") - .with_min_level(ndk_glue::log::Level::Warn) - ); - ndk_glue::init( - activity as _, - saved_state as _, - saved_state_size as _, - my_main, - ); - } - fn my_main() {} - }; - assert_eq!(actual.to_string(), expected.to_string()); - } - - #[test] - fn main_with_backtrace_on_and_logger_with_tag() { - let attr = MainAttr { - backtrace: Some(BacktraceProp::On), - logger: Some(LoggerProp { - tag: Some("my-tag".into()), - ..Default::default() - }), - ..Default::default() - }; - let item = parse_quote! { fn main() {} }; - let actual = attr.expand(&item); - let expected = quote! { - #[no_mangle] - unsafe extern "C" fn ANativeActivity_onCreate( - activity: *mut std::os::raw::c_void, - saved_state: *mut std::os::raw::c_void, - saved_state_size: usize, - ) { - std::env::set_var("RUST_BACKTRACE", "1"); - ndk_glue::android_logger::init_once( - ndk_glue::android_logger::Config::default() - .with_tag("my-tag") - ); - ndk_glue::init( - activity as _, - saved_state as _, - saved_state_size as _, - main, - ); - } - fn main() {} - }; - assert_eq!(actual.to_string(), expected.to_string()); - } - - #[test] - fn main_with_logger_with_overridden_ndk_glue_and_filter() { - let attr = MainAttr { - logger: Some(LoggerProp { - filter: Some("debug,hellow::world=trace".into()), - ..Default::default() - }), - ndk_glue: Some(parse_quote! { my::re::exported::ndk_glue }), - ..Default::default() - }; - let item = parse_quote! { fn main() {} }; - let actual = attr.expand(&item); - let expected = quote! { - #[no_mangle] - unsafe extern "C" fn ANativeActivity_onCreate( - activity: *mut std::os::raw::c_void, - saved_state: *mut std::os::raw::c_void, - saved_state_size: usize, - ) { - my::re::exported::ndk_glue::android_logger::init_once( - my::re::exported::ndk_glue::android_logger::Config::default() - .with_filter(my::re::exported::ndk_glue::android_logger::FilterBuilder::new().parse("debug,hellow::world=trace").build()) - ); - my::re::exported::ndk_glue::init( - activity as _, - saved_state as _, - saved_state_size as _, - main, - ); - } - fn main() {} - }; - assert_eq!(actual.to_string(), expected.to_string()); - } - - #[test] - fn main_with_logger_with_overridden_ndk_glue_and_log_level() { - let attr = MainAttr { - logger: Some(LoggerProp { - level: Some(LogLevel::Trace), - ..Default::default() - }), - ndk_glue: Some(parse_quote! { my::re::exported::ndk_glue }), - ..Default::default() - }; - let item = parse_quote! { fn main() {} }; - let actual = attr.expand(&item); - let expected = quote! { - #[no_mangle] - unsafe extern "C" fn ANativeActivity_onCreate( - activity: *mut std::os::raw::c_void, - saved_state: *mut std::os::raw::c_void, - saved_state_size: usize, - ) { - my::re::exported::ndk_glue::android_logger::init_once( - my::re::exported::ndk_glue::android_logger::Config::default() - .with_min_level(my::re::exported::ndk_glue::log::Level::Trace) - ); - my::re::exported::ndk_glue::init( - activity as _, - saved_state as _, - saved_state_size as _, - main, - ); - } - fn main() {} - }; - assert_eq!(actual.to_string(), expected.to_string()); - } - } -} diff --git a/ndk-macro/src/helper.rs b/ndk-macro/src/helper.rs deleted file mode 100644 index caf53bf9..00000000 --- a/ndk-macro/src/helper.rs +++ /dev/null @@ -1,66 +0,0 @@ -use core::ops::Deref; -use proc_macro2::{Ident, Span}; -use proc_macro_crate::FoundCrate; -use syn::{ - parse::{Parse, ParseStream, Result}, - Path, Token, -}; - -/// A newtype for testing -/// -/// This needed because AttributeArgs from syn crate is not a newtype and does not implements `Parse` trait -#[derive(Debug)] -pub struct AttributeArgs(syn::AttributeArgs); - -impl Deref for AttributeArgs { - type Target = syn::AttributeArgs; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Parse for AttributeArgs { - fn parse(input: ParseStream) -> Result { - let mut metas = Vec::new(); - - loop { - if input.is_empty() { - break; - } - let value = input.parse()?; - metas.push(value); - if input.is_empty() { - break; - } - input.parse::()?; - } - - Ok(Self(metas)) - } -} - -#[cfg(not(test))] -use proc_macro_crate::crate_name; - -#[cfg(test)] -fn crate_name(name: &str) -> Result { - Ok(FoundCrate::Name(name.replace('-', "_"))) -} - -pub fn crate_path(name: &str, overridden_path: &Option) -> Path { - // try to use overridden crate path - overridden_path.clone().unwrap_or_else(|| { - Ident::new( - // try to determine crate name from Cargo.toml - match crate_name(name) - .as_ref() - .expect("Crate not found in `Cargo.toml`") - { - FoundCrate::Itself => "ndk_macro", - FoundCrate::Name(n) => n.as_str(), - }, - Span::call_site(), - ) - .into() - }) -} diff --git a/ndk-macro/src/lib.rs b/ndk-macro/src/lib.rs deleted file mode 100644 index 19daf679..00000000 --- a/ndk-macro/src/lib.rs +++ /dev/null @@ -1,24 +0,0 @@ -#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] - -use darling::FromMeta; -use proc_macro::TokenStream; -use syn::{parse_macro_input, ItemFn}; - -mod expand; -mod helper; -mod parse; - -use helper::AttributeArgs; -use parse::MainAttr; - -#[proc_macro_attribute] -pub fn main(attr_input: TokenStream, item_input: TokenStream) -> TokenStream { - let item_ast = parse_macro_input!(item_input as ItemFn); - let attr_ast = parse_macro_input!(attr_input as AttributeArgs); - let attr: MainAttr = match FromMeta::from_list(&attr_ast) { - Ok(attr) => attr, - Err(errs) => return TokenStream::from(errs.write_errors()), - }; - - attr.expand(&item_ast).into() -} diff --git a/ndk-macro/src/parse.rs b/ndk-macro/src/parse.rs deleted file mode 100644 index 70d0cd55..00000000 --- a/ndk-macro/src/parse.rs +++ /dev/null @@ -1,197 +0,0 @@ -use darling::FromMeta; -use syn::Path; - -#[cfg(feature = "logger")] -pub use logger::{LogLevel, LoggerProp}; - -#[derive(Default, FromMeta, Debug)] -#[darling(default)] -pub struct MainAttr { - pub backtrace: Option, - // Path to `ndk_glue` to override - pub ndk_glue: Option, - #[cfg(feature = "logger")] - pub logger: Option, -} - -#[derive(FromMeta, PartialEq, Eq, Debug, Clone, Copy)] -#[darling(default)] -pub enum BacktraceProp { - On, - Full, -} - -impl Default for BacktraceProp { - fn default() -> Self { - BacktraceProp::On - } -} - -#[cfg(feature = "logger")] -mod logger { - use super::*; - - #[derive(FromMeta, PartialEq, Eq, Default, Debug, Clone)] - #[darling(default)] - pub struct LoggerProp { - // Minimum log level - pub level: Option, - // Tag name for logger - pub tag: Option, - // Filtering rules - pub filter: Option, - } - - #[derive(FromMeta, PartialEq, Eq, Debug, Clone, Copy)] - #[darling(default)] - pub enum LogLevel { - Error, - Warn, - Info, - Debug, - Trace, - } - - impl Default for LogLevel { - fn default() -> Self { - LogLevel::Error - } - } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::AttributeArgs; - use syn::parse_quote; - - #[test] - fn empty_attr() { - let attr: AttributeArgs = parse_quote! {}; - let attr: MainAttr = FromMeta::from_list(&attr).unwrap(); - - assert_eq!(attr.backtrace, None); - #[cfg(feature = "logger")] - assert_eq!(attr.logger, None); - } - - #[should_panic] - #[test] - fn invalid_attr() { - let attr: AttributeArgs = parse_quote! { - wrong - }; - let _attr: MainAttr = FromMeta::from_list(&attr).unwrap(); - } - - #[test] - fn backtrace_on() { - let attr: AttributeArgs = parse_quote! { - backtrace = "on" - }; - let attr: MainAttr = FromMeta::from_list(&attr).unwrap(); - - assert_eq!(attr.backtrace, Some(BacktraceProp::On)); - #[cfg(feature = "logger")] - assert_eq!(attr.logger, None); - } - - #[test] - fn backtrace_full() { - let attr: AttributeArgs = parse_quote! { - backtrace = "full" - }; - let attr: MainAttr = FromMeta::from_list(&attr).unwrap(); - - assert_eq!(attr.backtrace, Some(BacktraceProp::Full)); - #[cfg(feature = "logger")] - assert_eq!(attr.logger, None); - } - - #[test] - fn overridden_ndk_glue() { - let attr: AttributeArgs = parse_quote! { - ndk_glue = "my::re::exported::ndk_glue" - }; - let attr: MainAttr = FromMeta::from_list(&attr).unwrap(); - - let expected_path: Path = parse_quote! { - my::re::exported::ndk_glue - }; - - assert_eq!(attr.ndk_glue.unwrap(), expected_path); - } - - #[cfg(feature = "logger")] - mod logger { - use super::*; - - #[test] - fn logger_with_level() { - let attr: AttributeArgs = parse_quote! { - logger(level = "debug") - }; - let attr: MainAttr = FromMeta::from_list(&attr).unwrap(); - - let logger = attr.logger.unwrap(); - - assert_eq!(logger.level, Some(LogLevel::Debug)); - assert_eq!(logger.tag, None); - } - - #[test] - fn logger_with_tag() { - let attr: AttributeArgs = parse_quote! { - logger(tag = "my-tag") - }; - let attr: MainAttr = FromMeta::from_list(&attr).unwrap(); - - let logger = attr.logger.unwrap(); - - assert_eq!(logger.level, None); - assert_eq!(logger.tag.unwrap(), "my-tag"); - } - - #[test] - fn logger_with_filter() { - let attr: AttributeArgs = parse_quote! { - logger(filter = "debug,hello::world=trace") - }; - let attr: MainAttr = FromMeta::from_list(&attr).unwrap(); - - let logger = attr.logger.unwrap(); - - assert_eq!(logger.level, None); - assert_eq!(logger.filter.unwrap(), "debug,hello::world=trace"); - } - - #[test] - fn logger_with_level_and_with_tag() { - let attr: AttributeArgs = parse_quote! { - logger(level = "error", tag = "my-app") - }; - let attr: MainAttr = FromMeta::from_list(&attr).unwrap(); - - let logger = attr.logger.unwrap(); - - assert_eq!(logger.level, Some(LogLevel::Error)); - assert_eq!(logger.tag.unwrap(), "my-app"); - } - - #[test] - fn backtrace_on_and_logger_with_level_and_with_tag() { - let attr: AttributeArgs = parse_quote! { - logger(level = "warn", tag = "my-app"), - backtrace = "on" - }; - let attr: MainAttr = FromMeta::from_list(&attr).unwrap(); - - assert_eq!(attr.backtrace, Some(BacktraceProp::On)); - - let logger = attr.logger.unwrap(); - - assert_eq!(logger.level, Some(LogLevel::Warn)); - assert_eq!(logger.tag.unwrap(), "my-app"); - } - } -}