Simplify Iris app initialization and task updates

This commit is contained in:
iris committed 2026-09-11 12:28:33 -04:00
1 parent b5666cdef9
commit 166bac2a93
25 files changed
+330 -282

No files matched your search

+32 -13
View File
@@ -9,13 +9,15 @@ use syn::{
spanned::Spanned,
};
/// Marks the factory called when Android creates an Iris view.
/// Marks the initializer called when Android creates an Iris view.
///
/// An attribute is necessary here because the Android loader requires one
/// exported `JNI_OnLoad` symbol and `android-view` requires a plain function
/// pointer monomorphized for the returned application state. The generated
/// linker and JNI glue is Android-gated; the annotated function therefore
/// does not need its own `cfg` attribute.
/// pointer monomorphized for the application state. A function returning a
/// custom state remains its factory; a function with no return value receives
/// `&mut AndroidUiState` and uses that state directly. The generated linker and
/// JNI glue is Android-gated; the annotated function therefore does not need
/// its own `cfg` attribute.
#[proc_macro_attribute]
pub fn app_init(args: TokenStream, item: TokenStream) -> TokenStream {
if !args.is_empty() {
@@ -29,13 +31,9 @@ pub fn app_init(args: TokenStream, item: TokenStream) -> TokenStream {
let function = parse_macro_input!(item as ItemFn);
let name = &function.sig.ident;
let ReturnType::Type(_, state) = &function.sig.output else {
return Error::new(
function.sig.output.span(),
"an app_init function must return its application state",
)
.into_compile_error()
.into();
let (state, direct_initializer): (Type, bool) = match &function.sig.output {
ReturnType::Default => (parse_quote!(::iris::android::AndroidUiState), true),
ReturnType::Type(_, state) => ((**state).clone(), false),
};
if function.sig.inputs.len() != 2
|| function
@@ -46,7 +44,7 @@ pub fn app_init(args: TokenStream, item: TokenStream) -> TokenStream {
{
return Error::new(
function.sig.inputs.span(),
"an app_init function takes AndroidUiState and &mut State::Resources",
"an app_init function takes UI state and resources",
)
.into_compile_error()
.into();
@@ -64,6 +62,25 @@ pub fn app_init(args: TokenStream, item: TokenStream) -> TokenStream {
.into();
}
let factory = if direct_initializer {
quote! {
fn init(
mut ui_state: ::iris::android::AndroidUiState,
rsc: &mut <#state as ::iris::android::AndroidAppState>::Resources,
) -> #state {
super::#name(&mut ui_state, rsc);
ui_state
}
}
} else {
quote! {}
};
let create = if direct_initializer {
quote! { init }
} else {
quote! { super::#name }
};
quote! {
#[cfg(target_os = "android")]
#function
@@ -72,12 +89,14 @@ pub fn app_init(args: TokenStream, item: TokenStream) -> TokenStream {
mod __iris_android_app {
use super::*;
#factory
extern "system" fn new_view_peer<'local>(
env: ::iris::android::__private::JNIEnv<'local>,
view: ::iris::android::__private::View<'local>,
context: ::iris::android::__private::Context<'local>,
) -> ::iris::android::__private::JLong {
::iris::android::new_peer::<#state>(env, view, context, super::#name)
::iris::android::new_peer::<#state>(env, view, context, #create)
}
#[unsafe(no_mangle)]