openharmony_ability_derive/
lib.rs1use darling::FromMeta;
2use proc_macro::TokenStream;
3use syn::ItemFn;
4
5#[derive(FromMeta, Default, Debug)]
6struct AbilityArgs {
7 #[darling(default)]
8 webview: bool,
9 #[darling(default)]
10 protocol: Option<String>,
11}
12
13#[proc_macro_attribute]
14pub fn ability(attr: TokenStream, item: TokenStream) -> TokenStream {
15 let ast = syn::parse_macro_input!(item as ItemFn);
16 let fn_name = &ast.sig.ident;
17 let block = &ast.block;
18 let arg = &ast.sig.inputs;
19
20 let args = if attr.is_empty() {
21 AbilityArgs::default()
22 } else {
23 match darling::ast::NestedMeta::parse_meta_list(proc_macro2::TokenStream::from(attr)) {
24 Ok(list) => {
25 match AbilityArgs::from_list(&list) {
26 Ok(args) => args,
27 Err(e) => {
28 return TokenStream::from(e.write_errors());
29 }
30 }
31 }
32 Err(e) => {
33 return TokenStream::from(e.to_compile_error());
34 }
35 }
36 };
37
38 let protocol_registrations = args
39 .protocol
40 .as_ref()
41 .map(|protocols| {
42 protocols
43 .split(",")
44 .map(|protocol| {
45 let protocol_lit = syn::LitStr::new(protocol, proc_macro2::Span::call_site());
46 quote::quote! {
47 openharmony_ability::native_web::CustomProtocol::add_protocol(#protocol_lit);
48 }
49 })
50 .collect::<Vec<_>>()
51 })
52 .unwrap_or_default();
53
54 let render = if args.webview {
55 quote::quote! {
56 #[openharmony_ability::napi_derive::napi]
57 pub fn webview_render<'a>(
58 env: &'a openharmony_ability::napi::Env,
59 helper: openharmony_ability::napi::bindgen_prelude::ObjectRef,
60 ) -> openharmony_ability::napi::Result<openharmony_ability::WebViewComponentEventCallback<'a>> {
61 let callback = openharmony_ability::render(env, helper, (*APP).clone())?;
62 Ok(callback)
63 }
64 }
65 } else {
66 quote::quote! {
67 #[openharmony_ability::napi_derive::napi]
68 pub fn render<'a>(
69 env: &'a openharmony_ability::napi::Env,
70 helper: openharmony_ability::napi::bindgen_prelude::ObjectRef,
71 slot: openharmony_ability::arkui::ArkUIHandle,
72 ) -> openharmony_ability::napi::Result<()> {
73 let root = openharmony_ability::render(env, helper, slot, (*APP).clone())?;
74 ROOT_NODE.replace(Some(root));
75 Ok(())
76 }
77 }
78 };
79
80 let protocol_registrations_apply = if args.protocol.is_some() && args.webview {
82 quote::quote! {
83 #[openharmony_ability::napi_derive::napi]
84 pub fn register_custom_protocol<'a>(
85 env: &'a openharmony_ability::napi::Env,
86 ) -> openharmony_ability::napi::Result<()> {
87 #(#protocol_registrations)*
88
89 openharmony_ability::native_web::CustomProtocol::register();
90
91 Ok(())
92 }
93 }
94 } else {
95 quote::quote! {}
96 };
97
98 let f = quote::quote! {
99 pub(crate) fn #fn_name(#arg) #block
100
101 mod openharmony_ability_mod {
102 use super::*;
103 use openharmony_ability::napi as napi_ohos;
104
105 static APP: std::sync::LazyLock<openharmony_ability::OpenHarmonyApp> =
106 std::sync::LazyLock::new(|| openharmony_ability::OpenHarmonyApp::new());
107
108 thread_local! {
109 pub static ROOT_NODE: std::cell::RefCell<Option<openharmony_ability::arkui::RootNode>> = std::cell::RefCell::new(None);
110 }
111
112 #protocol_registrations_apply
113
114 #[openharmony_ability::napi_derive::napi]
115 pub fn init<'a>(
116 env: &'a openharmony_ability::napi::Env,
117 ) -> openharmony_ability::napi::Result<openharmony_ability::ApplicationLifecycle<'a>> {
118 let lifecycle_handle = openharmony_ability::create_lifecycle_handle(env, (*APP).clone())?;
119 #fn_name((*APP).clone());
120 Ok(lifecycle_handle)
121 }
122
123 #render
124 }
125 };
126
127 f.into()
128}