1use std::collections::HashMap;
2use std::sync::atomic::{AtomicU32, Ordering};
3
4use proc_macro2::{Ident, Literal, Span, TokenStream};
5use quote::ToTokens;
6
7use crate::{
8 codegen::{get_intermediate_ident, js_mod_to_token_stream},
9 BindgenResult, FnKind, NapiImpl, NapiStruct, NapiStructKind, TryToTokens,
10};
11use crate::{NapiArray, NapiClass, NapiObject, NapiStructuredEnum, NapiTransparent};
12
13static NAPI_IMPL_ID: AtomicU32 = AtomicU32::new(0);
14
15const STRUCT_FIELD_SPECIAL_CASE: &[&str] = &["Option", "Result"];
16
17fn gen_napi_value_map_impl(
19 name: &Ident,
20 to_napi_val_impl: TokenStream,
21 has_lifetime: bool,
22) -> TokenStream {
23 let name_str = name.to_string();
24 let name = if has_lifetime {
25 quote! { #name<'_> }
26 } else {
27 quote! { #name }
28 };
29 let js_name_str = format!("{name_str}\0");
30 let validate = quote! {
31 unsafe fn validate(env: napi_ohos::sys::napi_env, napi_val: napi_ohos::sys::napi_value) -> napi_ohos::Result<napi_ohos::sys::napi_value> {
32 if let Some(ctor_ref) = napi_ohos::bindgen_prelude::get_class_constructor(#js_name_str) {
33 let mut ctor = std::ptr::null_mut();
34 napi_ohos::check_status!(
35 napi_ohos::sys::napi_get_reference_value(env, ctor_ref, &mut ctor),
36 "Failed to get constructor reference of class `{}`",
37 #name_str
38 )?;
39 let mut is_instance_of = false;
40 napi_ohos::check_status!(
41 napi_ohos::sys::napi_instanceof(env, napi_val, ctor, &mut is_instance_of),
42 "Failed to get external value of class `{}`",
43 #name_str
44 )?;
45 if is_instance_of {
46 Ok(std::ptr::null_mut())
47 } else {
48 Err(napi_ohos::Error::new(
49 napi_ohos::Status::InvalidArg,
50 format!("Value is not instanceof class `{}`", #name_str)
51 ))
52 }
53 } else {
54 Err(napi_ohos::Error::new(
55 napi_ohos::Status::InvalidArg,
56 format!("Failed to get constructor of class `{}`", #name_str)
57 ))
58 }
59 }
60 };
61 quote! {
62 #[automatically_derived]
63 impl napi_ohos::bindgen_prelude::TypeName for #name {
64 fn type_name() -> &'static str {
65 #name_str
66 }
67
68 fn value_type() -> napi_ohos::ValueType {
69 napi_ohos::ValueType::Function
70 }
71 }
72
73 #[automatically_derived]
74 impl napi_ohos::bindgen_prelude::TypeName for &#name {
75 fn type_name() -> &'static str {
76 #name_str
77 }
78
79 fn value_type() -> napi_ohos::ValueType {
80 napi_ohos::ValueType::Object
81 }
82 }
83
84 #[automatically_derived]
85 impl napi_ohos::bindgen_prelude::TypeName for &mut #name {
86 fn type_name() -> &'static str {
87 #name_str
88 }
89
90 fn value_type() -> napi_ohos::ValueType {
91 napi_ohos::ValueType::Object
92 }
93 }
94
95 #to_napi_val_impl
96
97 #[automatically_derived]
98 impl napi_ohos::bindgen_prelude::FromNapiRef for #name {
99 unsafe fn from_napi_ref(
100 env: napi_ohos::bindgen_prelude::sys::napi_env,
101 napi_val: napi_ohos::bindgen_prelude::sys::napi_value
102 ) -> napi_ohos::bindgen_prelude::Result<&'static Self> {
103 let mut wrapped_val: *mut std::ffi::c_void = std::ptr::null_mut();
104
105 napi_ohos::bindgen_prelude::check_status!(
106 napi_ohos::bindgen_prelude::sys::napi_unwrap(env, napi_val, &mut wrapped_val),
107 "Failed to recover `{}` type from napi value",
108 #name_str,
109 )?;
110
111 Ok(&*(wrapped_val as *const #name))
112 }
113 }
114
115 #[automatically_derived]
116 impl napi_ohos::bindgen_prelude::FromNapiMutRef for #name {
117 unsafe fn from_napi_mut_ref(
118 env: napi_ohos::bindgen_prelude::sys::napi_env,
119 napi_val: napi_ohos::bindgen_prelude::sys::napi_value
120 ) -> napi_ohos::bindgen_prelude::Result<&'static mut Self> {
121 let mut wrapped_val: *mut std::ffi::c_void = std::ptr::null_mut();
122
123 napi_ohos::bindgen_prelude::check_status!(
124 napi_ohos::bindgen_prelude::sys::napi_unwrap(env, napi_val, &mut wrapped_val),
125 "Failed to recover `{}` type from napi value",
126 #name_str,
127 )?;
128
129 Ok(&mut *(wrapped_val as *mut #name))
130 }
131 }
132
133 #[automatically_derived]
134 impl napi_ohos::bindgen_prelude::ValidateNapiValue for &#name {
135 #validate
136 }
137
138 #[automatically_derived]
139 impl napi_ohos::bindgen_prelude::ValidateNapiValue for &mut #name {
140 #validate
141 }
142 }
143}
144
145impl TryToTokens for NapiStruct {
146 fn try_to_tokens(&self, tokens: &mut TokenStream) -> BindgenResult<()> {
147 let napi_value_map_impl = self.gen_napi_value_map_impl();
148
149 let class_helper_mod = match &self.kind {
150 NapiStructKind::Class(class) => self.gen_helper_mod(class),
151 _ => quote! {},
152 };
153
154 (quote! {
155 #napi_value_map_impl
156 #class_helper_mod
157 })
158 .to_tokens(tokens);
159
160 Ok(())
161 }
162}
163
164impl NapiStruct {
165 fn gen_helper_mod(&self, class: &NapiClass) -> TokenStream {
166 let mod_name = Ident::new(&format!("__napi_helper__{}", self.name), Span::call_site());
167
168 let ctor = if class.ctor {
169 self.gen_default_ctor(class)
170 } else {
171 quote! {}
172 };
173
174 let mut getters_setters = self.gen_default_getters_setters(class);
175 getters_setters.sort_by(|a, b| a.0.cmp(&b.0));
176 let register = self.gen_register(class);
177
178 let getters_setters_token = getters_setters.into_iter().map(|(_, token)| token);
179
180 quote! {
181 #[allow(clippy::all)]
182 #[allow(non_snake_case)]
183 mod #mod_name {
184 use std::ptr;
185 use super::*;
186
187 #ctor
188 #(#getters_setters_token)*
189 #register
190 }
191 }
192 }
193
194 fn gen_default_ctor(&self, class: &NapiClass) -> TokenStream {
195 let name = &self.name;
196 let js_name_str = &self.js_name;
197 let fields_len = class.fields.len();
198 let mut fields = vec![];
199
200 for (i, field) in class.fields.iter().enumerate() {
201 let ty = &field.ty;
202 match &field.name {
203 syn::Member::Named(ident) => fields
204 .push(quote! { #ident: <#ty as napi_ohos::bindgen_prelude::FromNapiValue>::from_napi_value(env, cb.get_arg(#i))? }),
205 syn::Member::Unnamed(_) => {
206 fields.push(quote! { <#ty as napi_ohos::bindgen_prelude::FromNapiValue>::from_napi_value(env, cb.get_arg(#i))? });
207 }
208 }
209 }
210
211 let construct = if class.is_tuple {
212 quote! { #name (#(#fields),*) }
213 } else {
214 quote! { #name {#(#fields),*} }
215 };
216
217 let is_empty_struct_hint = fields_len == 0;
218
219 let constructor = if class.implement_iterator {
220 quote! { unsafe { cb.construct_generator::<#is_empty_struct_hint, #name>(#js_name_str, #construct) } }
221 } else {
222 quote! { unsafe { cb.construct::<#is_empty_struct_hint, #name>(#js_name_str, #construct) } }
223 };
224
225 quote! {
226 extern "C" fn constructor(
227 env: napi_ohos::bindgen_prelude::sys::napi_env,
228 cb: napi_ohos::bindgen_prelude::sys::napi_callback_info
229 ) -> napi_ohos::bindgen_prelude::sys::napi_value {
230 napi_ohos::bindgen_prelude::CallbackInfo::<#fields_len>::new(env, cb, None, false)
231 .and_then(|cb| #constructor)
232 .unwrap_or_else(|e| {
233 unsafe { napi_ohos::bindgen_prelude::JsError::from(e).throw_into(env) };
234 std::ptr::null_mut::<napi_ohos::bindgen_prelude::sys::napi_value__>()
235 })
236 }
237 }
238 }
239
240 fn gen_napi_value_map_impl(&self) -> TokenStream {
241 match &self.kind {
242 NapiStructKind::Array(array) => self.gen_napi_value_array_impl(array),
243 NapiStructKind::Transparent(transparent) => self.gen_napi_value_transparent_impl(transparent),
244 NapiStructKind::Class(class) if !class.ctor => gen_napi_value_map_impl(
245 &self.name,
246 self.gen_to_napi_value_ctor_impl_for_non_default_constructor_struct(class),
247 self.has_lifetime,
248 ),
249 NapiStructKind::Class(class) => gen_napi_value_map_impl(
250 &self.name,
251 self.gen_to_napi_value_ctor_impl(class),
252 self.has_lifetime,
253 ),
254 NapiStructKind::Object(obj) => self.gen_to_napi_value_obj_impl(obj),
255 NapiStructKind::StructuredEnum(structured_enum) => {
256 self.gen_to_napi_value_structured_enum_impl(structured_enum)
257 }
258 }
259 }
260
261 fn gen_to_napi_value_ctor_impl_for_non_default_constructor_struct(
262 &self,
263 class: &NapiClass,
264 ) -> TokenStream {
265 let name = &self.name;
266 let js_name_raw = &self.js_name;
267 let js_name_str = format!("{js_name_raw}\0");
268 let iterator_implementation = self.gen_iterator_property(class, name);
269 let (object_finalize_impl, to_napi_value_impl, javascript_class_ext_impl) = if self.has_lifetime
270 {
271 let name = quote! { #name<'_javascript_function_scope> };
272 (
273 quote! { impl <'_javascript_function_scope> napi_ohos::bindgen_prelude::ObjectFinalize for #name {} },
274 quote! { impl <'_javascript_function_scope> napi_ohos::bindgen_prelude::ToNapiValue for #name },
275 quote! { impl <'_javascript_function_scope> napi_ohos::bindgen_prelude::JavaScriptClassExt for #name },
276 )
277 } else {
278 (
279 quote! { impl napi_ohos::bindgen_prelude::ObjectFinalize for #name {} },
280 quote! { impl napi_ohos::bindgen_prelude::ToNapiValue for #name },
281 quote! { impl napi_ohos::bindgen_prelude::JavaScriptClassExt for #name },
282 )
283 };
284 let finalize_trait = if class.use_custom_finalize {
285 quote! {}
286 } else {
287 quote! {
288 #[automatically_derived]
289 #object_finalize_impl
290 }
291 };
292 quote! {
293 #[automatically_derived]
294 #to_napi_value_impl {
295 unsafe fn to_napi_value(
296 env: napi_ohos::sys::napi_env,
297 val: #name
298 ) -> napi_ohos::Result<napi_ohos::bindgen_prelude::sys::napi_value> {
299 if let Some(ctor_ref) = napi_ohos::__private::get_class_constructor(#js_name_str) {
300 let mut wrapped_value = Box::into_raw(Box::new(val));
301 if wrapped_value as usize == 0x1 {
302 wrapped_value = Box::into_raw(Box::new(0u8)).cast();
303 }
304 let instance_value = napi_ohos::bindgen_prelude::new_instance::<#name>(env, wrapped_value.cast(), ctor_ref)?;
305 #iterator_implementation
306 Ok(instance_value)
307 } else {
308 Err(napi_ohos::bindgen_prelude::Error::new(
309 napi_ohos::bindgen_prelude::Status::InvalidArg, format!("Failed to get constructor of class `{}` in `ToNapiValue`", #js_name_raw))
310 )
311 }
312 }
313 }
314
315 #finalize_trait
316
317 #[automatically_derived]
318 #javascript_class_ext_impl {
319 fn into_instance<'scope>(self, env: &'scope napi_ohos::Env) -> napi_ohos::Result<napi_ohos::bindgen_prelude::ClassInstance<'scope, Self>>
320 {
321 if let Some(ctor_ref) = napi_ohos::bindgen_prelude::get_class_constructor(#js_name_str) {
322 unsafe {
323 let wrapped_value = Box::into_raw(Box::new(self));
324 let instance_value = napi_ohos::bindgen_prelude::new_instance::<#name>(env.raw(), wrapped_value as *mut _ as *mut std::ffi::c_void, ctor_ref)?;
325 Ok(napi_ohos::bindgen_prelude::ClassInstance::new(instance_value, env.raw(), wrapped_value))
326 }
327 } else {
328 Err(napi_ohos::bindgen_prelude::Error::new(
329 napi_ohos::bindgen_prelude::Status::InvalidArg, format!("Failed to get constructor of class `{}`", #js_name_raw))
330 )
331 }
332 }
333
334 fn into_reference(self, env: napi_ohos::Env) -> napi_ohos::Result<napi_ohos::bindgen_prelude::Reference<Self>> {
335 if let Some(ctor_ref) = napi_ohos::bindgen_prelude::get_class_constructor(#js_name_str) {
336 unsafe {
337 let mut wrapped_value = Box::into_raw(Box::new(self));
338 if wrapped_value as usize == 0x1 {
339 wrapped_value = Box::into_raw(Box::new(0u8)).cast();
340 }
341 let instance_value = napi_ohos::bindgen_prelude::new_instance::<#name>(env.raw(), wrapped_value.cast(), ctor_ref)?;
342 {
343 let env = env.raw();
344 #iterator_implementation
345 }
346 napi_ohos::bindgen_prelude::Reference::<#name>::from_value_ptr(wrapped_value.cast(), env.raw())
347 }
348 } else {
349 Err(napi_ohos::bindgen_prelude::Error::new(
350 napi_ohos::bindgen_prelude::Status::InvalidArg, format!("Failed to get constructor of class `{}`", #js_name_raw))
351 )
352 }
353 }
354
355 fn instance_of<'env, V: napi_ohos::JsValue<'env>>(env: &napi_ohos::bindgen_prelude::Env, value: &V) -> napi_ohos::bindgen_prelude::Result<bool> {
356 if let Some(ctor_ref) = napi_ohos::bindgen_prelude::get_class_constructor(#js_name_str) {
357 let mut ctor = std::ptr::null_mut();
358 napi_ohos::check_status!(
359 unsafe { napi_ohos::sys::napi_get_reference_value(env.raw(), ctor_ref, &mut ctor) },
360 "Failed to get constructor reference of class `{}`",
361 #js_name_str
362 )?;
363 let mut is_instance_of = false;
364 napi_ohos::check_status!(
365 unsafe { napi_ohos::sys::napi_instanceof(env.raw(), value.value().value, ctor, &mut is_instance_of) },
366 "Failed to run instanceof for class `{}`",
367 #js_name_str
368 )?;
369 Ok(is_instance_of)
370 } else {
371 Err(napi_ohos::Error::new(napi_ohos::Status::GenericFailure, format!("Failed to get constructor of class `{}`", #js_name_str)))
372 }
373 }
374 }
375 }
376 }
377
378 fn gen_iterator_property(&self, class: &NapiClass, name: &Ident) -> TokenStream {
379 if !class.implement_iterator {
380 return quote! {};
381 }
382 quote! {
383 unsafe { napi_ohos::__private::create_iterator::<#name>(env, instance_value, wrapped_value); }
384 }
385 }
386
387 fn gen_to_napi_value_ctor_impl(&self, class: &NapiClass) -> TokenStream {
388 let name = &self.name;
389 let js_name_without_null = &self.js_name;
390 let js_name_str = format!("{}\0", &self.js_name);
391
392 let mut field_conversions = vec![];
393 let mut field_destructions = vec![];
394
395 for field in class.fields.iter() {
396 let ty = &field.ty;
397
398 match &field.name {
399 syn::Member::Named(ident) => {
400 let alias_ident = format_ident!("{}_", ident);
402 field_destructions.push(quote! { #ident: #alias_ident });
403 field_conversions.push(
404 quote! { <#ty as napi_ohos::bindgen_prelude::ToNapiValue>::to_napi_value(env, #alias_ident)? },
405 );
406 }
407 syn::Member::Unnamed(i) => {
408 let arg_name = format_ident!("arg{}", i);
409 field_destructions.push(quote! { #arg_name });
410 field_conversions.push(
411 quote! { <#ty as napi_ohos::bindgen_prelude::ToNapiValue>::to_napi_value(env, #arg_name)? },
412 );
413 }
414 }
415 }
416
417 let destructed_fields = if class.is_tuple {
418 quote! {
419 Self (#(#field_destructions),*)
420 }
421 } else {
422 quote! {
423 Self {#(#field_destructions),*}
424 }
425 };
426
427 let finalize_trait = if class.use_custom_finalize {
428 quote! {}
429 } else if self.has_lifetime {
430 quote! { impl <'_javascript_function_scope> napi_ohos::bindgen_prelude::ObjectFinalize for #name<'_javascript_function_scope> {} }
431 } else {
432 quote! { impl napi_ohos::bindgen_prelude::ObjectFinalize for #name {} }
433 };
434
435 let to_napi_value_impl = if self.has_lifetime {
436 quote! { impl <'_javascript_function_scope> napi_ohos::bindgen_prelude::ToNapiValue for #name<'_javascript_function_scope> }
437 } else {
438 quote! { impl napi_ohos::bindgen_prelude::ToNapiValue for #name }
439 };
440
441 quote! {
442 #[automatically_derived]
443 #to_napi_value_impl {
444 unsafe fn to_napi_value(
445 env: napi_ohos::bindgen_prelude::sys::napi_env,
446 val: #name,
447 ) -> napi_ohos::bindgen_prelude::Result<napi_ohos::bindgen_prelude::sys::napi_value> {
448 if let Some(ctor_ref) = napi_ohos::bindgen_prelude::get_class_constructor(#js_name_str) {
449 let mut ctor = std::ptr::null_mut();
450
451 napi_ohos::bindgen_prelude::check_status!(
452 napi_ohos::bindgen_prelude::sys::napi_get_reference_value(env, ctor_ref, &mut ctor),
453 "Failed to get constructor reference of class `{}`",
454 #js_name_without_null
455 )?;
456
457 let mut instance_value = std::ptr::null_mut();
458 let #destructed_fields = val;
459 let args = vec![#(#field_conversions),*];
460
461 napi_ohos::bindgen_prelude::check_status!(
462 napi_ohos::bindgen_prelude::sys::napi_new_instance(env, ctor, args.len(), args.as_ptr(), &mut instance_value),
463 "Failed to construct class `{}`",
464 #js_name_without_null
465 )?;
466
467 Ok(instance_value)
468 } else {
469 Err(napi_ohos::bindgen_prelude::Error::new(
470 napi_ohos::bindgen_prelude::Status::InvalidArg, format!("Failed to get constructor of class `{}`", #js_name_str))
471 )
472 }
473 }
474 }
475 #finalize_trait
476 }
477 }
478
479 fn gen_to_napi_value_obj_impl(&self, obj: &NapiObject) -> TokenStream {
480 let name = &self.name;
481 let name_str = self.name.to_string();
482
483 let mut obj_field_setters = vec![];
484 let mut obj_field_getters = vec![];
485 let mut field_destructions = vec![];
486
487 for field in obj.fields.iter() {
488 let field_js_name = &field.js_name;
489 let mut ty = field.ty.clone();
490 remove_lifetime_in_type(&mut ty);
491 let is_optional_field = if let syn::Type::Path(syn::TypePath {
492 path: syn::Path { segments, .. },
493 ..
494 }) = &ty
495 {
496 if let Some(last_path) = segments.last() {
497 last_path.ident == "Option"
498 } else {
499 false
500 }
501 } else {
502 false
503 };
504 match &field.name {
505 syn::Member::Named(ident) => {
506 let alias_ident = format_ident!("{}_", ident);
507 field_destructions.push(quote! { #ident: #alias_ident });
508 if is_optional_field {
509 obj_field_setters.push(match self.use_nullable {
510 false => quote! {
511 if #alias_ident.is_some() {
512 obj.set(#field_js_name, #alias_ident)?;
513 }
514 },
515 true => quote! {
516 if let Some(#alias_ident) = #alias_ident {
517 obj.set(#field_js_name, #alias_ident)?;
518 } else {
519 obj.set(#field_js_name, napi_ohos::bindgen_prelude::Null)?;
520 }
521 },
522 });
523 } else {
524 obj_field_setters.push(quote! { obj.set(#field_js_name, #alias_ident)?; });
525 }
526 if is_optional_field && !self.use_nullable {
527 obj_field_getters.push(quote! {
528 let #alias_ident: #ty = obj.get(#field_js_name).map_err(|mut err| {
529 err.reason = format!("{} on {}.{}", err.reason, #name_str, #field_js_name);
530 err
531 })?;
532 });
533 } else {
534 obj_field_getters.push(quote! {
535 let #alias_ident: #ty = obj.get(#field_js_name).map_err(|mut err| {
536 err.reason = format!("{} on {}.{}", err.reason, #name_str, #field_js_name);
537 err
538 })?.ok_or_else(|| napi_ohos::bindgen_prelude::Error::new(
539 napi_ohos::bindgen_prelude::Status::InvalidArg,
540 format!("Missing field `{}`", #field_js_name),
541 ))?;
542 });
543 }
544 }
545 syn::Member::Unnamed(i) => {
546 let arg_name = format_ident!("arg{}", i);
547 field_destructions.push(quote! { #arg_name });
548 if is_optional_field {
549 obj_field_setters.push(match self.use_nullable {
550 false => quote! {
551 if #arg_name.is_some() {
552 obj.set(#field_js_name, #arg_name)?;
553 }
554 },
555 true => quote! {
556 if let Some(#arg_name) = #arg_name {
557 obj.set(#field_js_name, #arg_name)?;
558 } else {
559 obj.set(#field_js_name, napi_ohos::bindgen_prelude::Null)?;
560 }
561 },
562 });
563 } else {
564 obj_field_setters.push(quote! { obj.set(#field_js_name, #arg_name)?; });
565 }
566 if is_optional_field && !self.use_nullable {
567 obj_field_getters.push(quote! { let #arg_name: #ty = obj.get(#field_js_name)?; });
568 } else {
569 obj_field_getters.push(quote! {
570 let #arg_name: #ty = obj.get(#field_js_name)?.ok_or_else(|| napi_ohos::bindgen_prelude::Error::new(
571 napi_ohos::bindgen_prelude::Status::InvalidArg,
572 format!("Missing field `{}`", #field_js_name),
573 ))?;
574 });
575 }
576 }
577 }
578 }
579
580 let destructed_fields = if obj.is_tuple {
581 quote! {
582 Self (#(#field_destructions),*)
583 }
584 } else {
585 quote! {
586 Self {#(#field_destructions),*}
587 }
588 };
589
590 let name_with_lifetime = if self.has_lifetime {
591 quote! { #name<'_javascript_function_scope> }
592 } else {
593 quote! { #name }
594 };
595 let (from_napi_value_impl, to_napi_value_impl, validate_napi_value_impl, type_name_impl) =
596 if self.has_lifetime {
597 (
598 quote! { impl <'_javascript_function_scope> napi_ohos::bindgen_prelude::FromNapiValue for #name<'_javascript_function_scope> },
599 quote! { impl <'_javascript_function_scope> napi_ohos::bindgen_prelude::ToNapiValue for #name<'_javascript_function_scope> },
600 quote! { impl <'_javascript_function_scope> napi_ohos::bindgen_prelude::ValidateNapiValue for #name<'_javascript_function_scope> },
601 quote! { impl <'_javascript_function_scope> napi_ohos::bindgen_prelude::TypeName for #name<'_javascript_function_scope> },
602 )
603 } else {
604 (
605 quote! { impl napi_ohos::bindgen_prelude::FromNapiValue for #name },
606 quote! { impl napi_ohos::bindgen_prelude::ToNapiValue for #name },
607 quote! { impl napi_ohos::bindgen_prelude::ValidateNapiValue for #name },
608 quote! { impl napi_ohos::bindgen_prelude::TypeName for #name },
609 )
610 };
611
612 let to_napi_value = if obj.object_to_js {
613 quote! {
614 #[automatically_derived]
615 #to_napi_value_impl {
616 unsafe fn to_napi_value(env: napi_ohos::bindgen_prelude::sys::napi_env, val: #name_with_lifetime) -> napi_ohos::bindgen_prelude::Result<napi_ohos::bindgen_prelude::sys::napi_value> {
617 #[allow(unused_variables)]
618 let env_wrapper = napi_ohos::bindgen_prelude::Env::from(env);
619 #[allow(unused_mut)]
620 let mut obj = napi_ohos::bindgen_prelude::Object::new(&env_wrapper)?;
621
622 let #destructed_fields = val;
623 #(#obj_field_setters)*
624
625 napi_ohos::bindgen_prelude::Object::to_napi_value(env, obj)
626 }
627 }
628 }
629 } else {
630 quote! {}
631 };
632
633 let from_napi_value = if obj.object_from_js {
634 let return_type = if self.has_lifetime {
635 quote! { #name<'_javascript_function_scope> }
636 } else {
637 quote! { #name }
638 };
639 quote! {
640 #[automatically_derived]
641 #from_napi_value_impl {
642 unsafe fn from_napi_value(
643 env: napi_ohos::bindgen_prelude::sys::napi_env,
644 napi_val: napi_ohos::bindgen_prelude::sys::napi_value
645 ) -> napi_ohos::bindgen_prelude::Result<#return_type> {
646 #[allow(unused_variables)]
647 let env_wrapper = napi_ohos::bindgen_prelude::Env::from(env);
648 #[allow(unused_mut)]
649 let mut obj = napi_ohos::bindgen_prelude::Object::from_napi_value(env, napi_val)?;
650
651 #(#obj_field_getters)*
652
653 let val = #destructed_fields;
654
655 Ok(val)
656 }
657 }
658
659 #[automatically_derived]
660 #validate_napi_value_impl {}
661 }
662 } else {
663 quote! {}
664 };
665
666 quote! {
667 #[automatically_derived]
668 #type_name_impl {
669 fn type_name() -> &'static str {
670 #name_str
671 }
672
673 fn value_type() -> napi_ohos::ValueType {
674 napi_ohos::ValueType::Object
675 }
676 }
677
678 #to_napi_value
679
680 #from_napi_value
681 }
682 }
683
684 fn gen_default_getters_setters(&self, class: &NapiClass) -> Vec<(String, TokenStream)> {
685 let mut getters_setters = vec![];
686 let struct_name = &self.name;
687
688 for field in class.fields.iter() {
689 let field_ident = &field.name;
690 let field_name = match &field.name {
691 syn::Member::Named(ident) => ident.to_string(),
692 syn::Member::Unnamed(i) => format!("field{}", i.index),
693 };
694 let ty = &field.ty;
695
696 let getter_name = Ident::new(
697 &format!("get_{}", rm_raw_prefix(&field_name)),
698 Span::call_site(),
699 );
700 let setter_name = Ident::new(
701 &format!("set_{}", rm_raw_prefix(&field_name)),
702 Span::call_site(),
703 );
704
705 if field.getter {
706 let default_to_napi_value_convert = quote! {
707 let val = &mut obj.#field_ident;
708 unsafe { <&mut #ty as napi_ohos::bindgen_prelude::ToNapiValue>::to_napi_value(env, val) }
709 };
710 let to_napi_value_convert = if let syn::Type::Path(syn::TypePath {
711 path: syn::Path { segments, .. },
712 ..
713 }) = ty
714 {
715 if let Some(syn::PathSegment { ident, .. }) = segments.last() {
716 if STRUCT_FIELD_SPECIAL_CASE.iter().any(|name| ident == name) {
717 quote! {
718 let val = obj.#field_ident.as_mut();
719 unsafe { napi_ohos::bindgen_prelude::ToNapiValue::to_napi_value(env, val) }
720 }
721 } else {
722 default_to_napi_value_convert
723 }
724 } else {
725 default_to_napi_value_convert
726 }
727 } else {
728 default_to_napi_value_convert
729 };
730 getters_setters.push((
731 field.js_name.clone(),
732 quote! {
733 extern "C" fn #getter_name(
734 env: napi_ohos::bindgen_prelude::sys::napi_env,
735 cb: napi_ohos::bindgen_prelude::sys::napi_callback_info
736 ) -> napi_ohos::bindgen_prelude::sys::napi_value {
737 napi_ohos::bindgen_prelude::CallbackInfo::<0>::new(env, cb, Some(0), false)
738 .and_then(|mut cb| cb.unwrap_borrow_mut::<#struct_name>())
739 .and_then(|obj| {
740 #to_napi_value_convert
741 })
742 .unwrap_or_else(|e| {
743 unsafe { napi_ohos::bindgen_prelude::JsError::from(e).throw_into(env) };
744 std::ptr::null_mut::<napi_ohos::bindgen_prelude::sys::napi_value__>()
745 })
746 }
747 },
748 ));
749 }
750
751 if field.setter {
752 getters_setters.push((
753 field.js_name.clone(),
754 quote! {
755 extern "C" fn #setter_name(
756 env: napi_ohos::bindgen_prelude::sys::napi_env,
757 cb: napi_ohos::bindgen_prelude::sys::napi_callback_info
758 ) -> napi_ohos::bindgen_prelude::sys::napi_value {
759 napi_ohos::bindgen_prelude::CallbackInfo::<1>::new(env, cb, Some(1), false)
760 .and_then(|mut cb_info| unsafe {
761 cb_info.unwrap_borrow_mut::<#struct_name>()
762 .and_then(|obj| {
763 <#ty as napi_ohos::bindgen_prelude::FromNapiValue>::from_napi_value(env, cb_info.get_arg(0))
764 .and_then(move |val| {
765 obj.#field_ident = val;
766 <() as napi_ohos::bindgen_prelude::ToNapiValue>::to_napi_value(env, ())
767 })
768 })
769 })
770 .unwrap_or_else(|e| {
771 unsafe { napi_ohos::bindgen_prelude::JsError::from(e).throw_into(env) };
772 std::ptr::null_mut::<napi_ohos::bindgen_prelude::sys::napi_value__>()
773 })
774 }
775 },
776 ));
777 }
778 }
779
780 getters_setters
781 }
782
783 fn gen_register(&self, class: &NapiClass) -> TokenStream {
784 let name = &self.name;
785 let struct_register_name = &self.register_name;
786 let js_name = format!("{}\0", self.js_name);
787 let mut props = vec![];
788
789 if class.ctor {
790 props.push(quote! { napi_ohos::bindgen_prelude::Property::new().with_utf8_name("constructor").unwrap().with_ctor(constructor) });
791 }
792
793 for field in class.fields.iter() {
794 let field_name = match &field.name {
795 syn::Member::Named(ident) => ident.to_string(),
796 syn::Member::Unnamed(i) => format!("field{}", i.index),
797 };
798
799 if !field.getter {
800 continue;
801 }
802
803 let js_name = &field.js_name;
804 let mut attribute = super::PROPERTY_ATTRIBUTE_DEFAULT;
805 if field.writable {
806 attribute |= super::PROPERTY_ATTRIBUTE_WRITABLE;
807 }
808 if field.enumerable {
809 attribute |= super::PROPERTY_ATTRIBUTE_ENUMERABLE;
810 }
811 if field.configurable {
812 attribute |= super::PROPERTY_ATTRIBUTE_CONFIGURABLE;
813 }
814
815 let mut prop = quote! {
816 napi_ohos::bindgen_prelude::Property::new().with_utf8_name(#js_name)
817 .unwrap()
818 .with_property_attributes(napi_ohos::bindgen_prelude::PropertyAttributes::from_bits(#attribute).unwrap())
819 };
820
821 if field.getter {
822 let getter_name = Ident::new(
823 &format!("get_{}", rm_raw_prefix(&field_name)),
824 Span::call_site(),
825 );
826 (quote! { .with_getter(#getter_name) }).to_tokens(&mut prop);
827 }
828
829 if field.writable && field.setter {
830 let setter_name = Ident::new(
831 &format!("set_{}", rm_raw_prefix(&field_name)),
832 Span::call_site(),
833 );
834 (quote! { .with_setter(#setter_name) }).to_tokens(&mut prop);
835 }
836
837 props.push(prop);
838 }
839 let js_mod_ident = js_mod_to_token_stream(self.js_mod.as_ref());
840 quote! {
841 #[allow(non_snake_case)]
842 #[allow(clippy::all)]
843 #[cfg(all(not(test), not(target_family = "wasm")))]
844 #[napi_ohos::ctor::ctor(crate_path=napi_ohos::ctor)]
845 fn #struct_register_name() {
846 napi_ohos::__private::register_class(std::any::TypeId::of::<#name>(), #js_mod_ident, #js_name, vec![#(#props),*]);
847 }
848
849 #[allow(non_snake_case)]
850 #[allow(clippy::all)]
851 #[cfg(all(not(test), target_family = "wasm"))]
852 #[no_mangle]
853 extern "C" fn #struct_register_name() {
854 napi_ohos::__private::register_class(std::any::TypeId::of::<#name>(), #js_mod_ident, #js_name, vec![#(#props),*]);
855 }
856 }
857 }
858
859 fn gen_to_napi_value_structured_enum_impl(
860 &self,
861 structured_enum: &NapiStructuredEnum,
862 ) -> TokenStream {
863 let name = &self.name;
864 let name_str = self.name.to_string();
865 let discriminant = structured_enum.discriminant.as_str();
866
867 let mut variant_arm_setters = vec![];
868 let mut variant_arm_getters = vec![];
869
870 for variant in structured_enum.variants.iter() {
871 let variant_name = &variant.name;
872 let variant_name_str = variant_name.to_string();
873 let mut obj_field_setters = vec![quote! {
874 obj.set(#discriminant, #variant_name_str)?;
875 }];
876 let mut obj_field_getters = vec![];
877 let mut field_destructions = vec![];
878 for field in variant.fields.iter() {
879 let field_js_name = &field.js_name;
880 let mut ty = field.ty.clone();
881 remove_lifetime_in_type(&mut ty);
882 let is_optional_field = if let syn::Type::Path(syn::TypePath {
883 path: syn::Path { segments, .. },
884 ..
885 }) = &ty
886 {
887 if let Some(last_path) = segments.last() {
888 last_path.ident == "Option"
889 } else {
890 false
891 }
892 } else {
893 false
894 };
895 match &field.name {
896 syn::Member::Named(ident) => {
897 let alias_ident = format_ident!("{}_", ident);
898 field_destructions.push(quote! { #ident: #alias_ident });
899 if is_optional_field {
900 obj_field_setters.push(match self.use_nullable {
901 false => quote! {
902 if #alias_ident.is_some() {
903 obj.set(#field_js_name, #alias_ident)?;
904 }
905 },
906 true => quote! {
907 if let Some(#alias_ident) = #alias_ident {
908 obj.set(#field_js_name, #alias_ident)?;
909 } else {
910 obj.set(#field_js_name, napi_ohos::bindgen_prelude::Null)?;
911 }
912 },
913 });
914 } else {
915 obj_field_setters.push(quote! { obj.set(#field_js_name, #alias_ident)?; });
916 }
917 if is_optional_field && !self.use_nullable {
918 obj_field_getters.push(quote! {
919 let #alias_ident: #ty = obj.get(#field_js_name).map_err(|mut err| {
920 err.reason = format!("{} on {}.{}", err.reason, #name_str, #field_js_name);
921 err
922 })?;
923 });
924 } else {
925 obj_field_getters.push(quote! {
926 let #alias_ident: #ty = obj.get(#field_js_name).map_err(|mut err| {
927 err.reason = format!("{} on {}.{}", err.reason, #name_str, #field_js_name);
928 err
929 })?.ok_or_else(|| napi_ohos::bindgen_prelude::Error::new(
930 napi_ohos::bindgen_prelude::Status::InvalidArg,
931 format!("Missing field `{}`", #field_js_name),
932 ))?;
933 });
934 }
935 }
936 syn::Member::Unnamed(i) => {
937 let arg_name = format_ident!("arg{}", i);
938 field_destructions.push(quote! { #arg_name });
939 if is_optional_field {
940 obj_field_setters.push(match self.use_nullable {
941 false => quote! {
942 if #arg_name.is_some() {
943 obj.set(#field_js_name, #arg_name)?;
944 }
945 },
946 true => quote! {
947 if let Some(#arg_name) = #arg_name {
948 obj.set(#field_js_name, #arg_name)?;
949 } else {
950 obj.set(#field_js_name, napi_ohos::bindgen_prelude::Null)?;
951 }
952 },
953 });
954 } else {
955 obj_field_setters.push(quote! { obj.set(#field_js_name, #arg_name)?; });
956 }
957 if is_optional_field && !self.use_nullable {
958 obj_field_getters.push(quote! { let #arg_name: #ty = obj.get(#field_js_name)?; });
959 } else {
960 obj_field_getters.push(quote! {
961 let #arg_name: #ty = obj.get(#field_js_name)?.ok_or_else(|| napi_ohos::bindgen_prelude::Error::new(
962 napi_ohos::bindgen_prelude::Status::InvalidArg,
963 format!("Missing field `{}`", #field_js_name),
964 ))?;
965 });
966 }
967 }
968 }
969 }
970
971 let destructed_fields = if variant.is_tuple {
972 quote! {
973 Self::#variant_name (#(#field_destructions),*)
974 }
975 } else {
976 quote! {
977 Self::#variant_name {#(#field_destructions),*}
978 }
979 };
980
981 variant_arm_setters.push(quote! {
982 #destructed_fields => {
983 #(#obj_field_setters)*
984 },
985 });
986
987 variant_arm_getters.push(quote! {
988 #variant_name_str => {
989 #(#obj_field_getters)*
990 #destructed_fields
991 },
992 })
993 }
994
995 let to_napi_value = if structured_enum.object_to_js {
996 quote! {
997 impl napi_ohos::bindgen_prelude::ToNapiValue for #name {
998 unsafe fn to_napi_value(env: napi_ohos::bindgen_prelude::sys::napi_env, val: #name) -> napi_ohos::bindgen_prelude::Result<napi_ohos::bindgen_prelude::sys::napi_value> {
999 #[allow(unused_variables)]
1000 let env_wrapper = napi_ohos::bindgen_prelude::Env::from(env);
1001 #[allow(unused_mut)]
1002 let mut obj = napi_ohos::bindgen_prelude::Object::new(&env_wrapper)?;
1003 match val {
1004 #(#variant_arm_setters)*
1005 };
1006
1007 napi_ohos::bindgen_prelude::Object::to_napi_value(env, obj)
1008 }
1009 }
1010 }
1011 } else {
1012 quote! {}
1013 };
1014
1015 let from_napi_value = if structured_enum.object_from_js {
1016 quote! {
1017 impl napi_ohos::bindgen_prelude::FromNapiValue for #name {
1018 unsafe fn from_napi_value(
1019 env: napi_ohos::bindgen_prelude::sys::napi_env,
1020 napi_val: napi_ohos::bindgen_prelude::sys::napi_value
1021 ) -> napi_ohos::bindgen_prelude::Result<Self> {
1022 #[allow(unused_variables)]
1023 let env_wrapper = napi_ohos::bindgen_prelude::Env::from(env);
1024 #[allow(unused_mut)]
1025 let mut obj = napi_ohos::bindgen_prelude::Object::from_napi_value(env, napi_val)?;
1026 let type_: String = obj.get(#discriminant).map_err(|mut err| {
1027 err.reason = format!("{} on {}.{}", err.reason, #name_str, #discriminant);
1028 err
1029 })?.ok_or_else(|| napi_ohos::bindgen_prelude::Error::new(
1030 napi_ohos::bindgen_prelude::Status::InvalidArg,
1031 format!("Missing field `{}`", #discriminant),
1032 ))?;
1033 let val = match type_.as_str() {
1034 #(#variant_arm_getters)*
1035 _ => return Err(napi_ohos::bindgen_prelude::Error::new(
1036 napi_ohos::bindgen_prelude::Status::InvalidArg,
1037 format!("Unknown variant `{}`", type_),
1038 )),
1039 };
1040
1041 Ok(val)
1042 }
1043 }
1044
1045 impl napi_ohos::bindgen_prelude::ValidateNapiValue for #name {}
1046 }
1047 } else {
1048 quote! {}
1049 };
1050
1051 quote! {
1052 impl napi_ohos::bindgen_prelude::TypeName for #name {
1053 fn type_name() -> &'static str {
1054 #name_str
1055 }
1056
1057 fn value_type() -> napi_ohos::ValueType {
1058 napi_ohos::ValueType::Object
1059 }
1060 }
1061
1062 #to_napi_value
1063
1064 #from_napi_value
1065 }
1066 }
1067
1068 fn gen_napi_value_transparent_impl(&self, transparent: &NapiTransparent) -> TokenStream {
1069 let name = &self.name;
1070 let name = if self.has_lifetime {
1071 quote! { #name<'_> }
1072 } else {
1073 quote! { #name }
1074 };
1075 let inner_type = transparent.ty.clone().into_token_stream();
1076
1077 let to_napi_value = if transparent.object_to_js {
1078 quote! {
1079 #[automatically_derived]
1080 impl napi_ohos::bindgen_prelude::ToNapiValue for #name {
1081 unsafe fn to_napi_value(
1082 env: napi_ohos::bindgen_prelude::sys::napi_env,
1083 val: Self
1084 ) -> napi_ohos::bindgen_prelude::Result<napi_ohos::bindgen_prelude::sys::napi_value> {
1085 <#inner_type>::to_napi_value(env, val.0)
1086 }
1087 }
1088 }
1089 } else {
1090 quote! {}
1091 };
1092
1093 let from_napi_value = if transparent.object_from_js {
1094 quote! {
1095 #[automatically_derived]
1096 impl napi_ohos::bindgen_prelude::FromNapiValue for #name {
1097 unsafe fn from_napi_value(
1098 env: napi_ohos::bindgen_prelude::sys::napi_env,
1099 napi_val: napi_ohos::bindgen_prelude::sys::napi_value
1100 ) -> napi_ohos::bindgen_prelude::Result<Self> {
1101 Ok(Self(<#inner_type>::from_napi_value(env, napi_val)?))
1102 }
1103 }
1104 }
1105 } else {
1106 quote! {}
1107 };
1108
1109 quote! {
1110 #[automatically_derived]
1111 impl napi_ohos::bindgen_prelude::TypeName for #name {
1112 fn type_name() -> &'static str {
1113 <#inner_type>::type_name()
1114 }
1115
1116 fn value_type() -> napi_ohos::ValueType {
1117 <#inner_type>::value_type()
1118 }
1119 }
1120
1121 #[automatically_derived]
1122 impl napi_ohos::bindgen_prelude::ValidateNapiValue for #name {
1123 unsafe fn validate(
1124 env: napi_ohos::bindgen_prelude::sys::napi_env,
1125 napi_val: napi_ohos::bindgen_prelude::sys::napi_value
1126 ) -> napi_ohos::bindgen_prelude::Result<napi_ohos::sys::napi_value> {
1127 <#inner_type>::validate(env, napi_val)
1128 }
1129 }
1130
1131 #to_napi_value
1132
1133 #from_napi_value
1134 }
1135 }
1136
1137 fn gen_napi_value_array_impl(&self, array: &NapiArray) -> TokenStream {
1138 let name = &self.name;
1139 let name_str = self.name.to_string();
1140
1141 let mut obj_field_setters = vec![];
1142 let mut obj_field_getters = vec![];
1143 let mut field_destructions = vec![];
1144
1145 for field in array.fields.iter() {
1146 let mut ty = field.ty.clone();
1147 remove_lifetime_in_type(&mut ty);
1148 let is_optional_field = if let syn::Type::Path(syn::TypePath {
1149 path: syn::Path { segments, .. },
1150 ..
1151 }) = &ty
1152 {
1153 if let Some(last_path) = segments.last() {
1154 last_path.ident == "Option"
1155 } else {
1156 false
1157 }
1158 } else {
1159 false
1160 };
1161
1162 if let syn::Member::Unnamed(i) = &field.name {
1163 let arg_name = format_ident!("arg{}", i);
1164 let field_index = i.index;
1165 field_destructions.push(quote! { #arg_name });
1166 if is_optional_field {
1167 obj_field_setters.push(match self.use_nullable {
1168 false => quote! {
1169 if #arg_name.is_some() {
1170 array.set(#field_index, #arg_name)?;
1171 }
1172 },
1173 true => quote! {
1174 if let Some(#arg_name) = #arg_name {
1175 array.set(#field_index, #arg_name)?;
1176 } else {
1177 array.set(#field_index, napi_ohos::bindgen_prelude::Null)?;
1178 }
1179 },
1180 });
1181 } else {
1182 obj_field_setters.push(quote! { array.set(#field_index, #arg_name)?; });
1183 }
1184 if is_optional_field && !self.use_nullable {
1185 obj_field_getters.push(quote! { let #arg_name: #ty = array.get(#field_index)?; });
1186 } else {
1187 obj_field_getters.push(quote! {
1188 let #arg_name: #ty = array.get(#field_index)?.ok_or_else(|| napi_ohos::bindgen_prelude::Error::new(
1189 napi_ohos::bindgen_prelude::Status::InvalidArg,
1190 format!("Failed to get element with index `{}`", #field_index),
1191 ))?;
1192 });
1193 }
1194 }
1195 }
1196
1197 let destructed_fields = quote! {
1198 Self (#(#field_destructions),*)
1199 };
1200
1201 let name_with_lifetime = if self.has_lifetime {
1202 quote! { #name<'_javascript_function_scope> }
1203 } else {
1204 quote! { #name }
1205 };
1206 let (from_napi_value_impl, to_napi_value_impl, validate_napi_value_impl, type_name_impl) =
1207 if self.has_lifetime {
1208 (
1209 quote! { impl <'_javascript_function_scope> napi_ohos::bindgen_prelude::FromNapiValue for #name<'_javascript_function_scope> },
1210 quote! { impl <'_javascript_function_scope> napi_ohos::bindgen_prelude::ToNapiValue for #name<'_javascript_function_scope> },
1211 quote! { impl <'_javascript_function_scope> napi_ohos::bindgen_prelude::ValidateNapiValue for #name<'_javascript_function_scope> },
1212 quote! { impl <'_javascript_function_scope> napi_ohos::bindgen_prelude::TypeName for #name<'_javascript_function_scope> },
1213 )
1214 } else {
1215 (
1216 quote! { impl napi_ohos::bindgen_prelude::FromNapiValue for #name },
1217 quote! { impl napi_ohos::bindgen_prelude::ToNapiValue for #name },
1218 quote! { impl napi_ohos::bindgen_prelude::ValidateNapiValue for #name },
1219 quote! { impl napi_ohos::bindgen_prelude::TypeName for #name },
1220 )
1221 };
1222
1223 let array_len = array.fields.len() as u32;
1224
1225 let to_napi_value = if array.object_to_js {
1226 quote! {
1227 #[automatically_derived]
1228 #to_napi_value_impl {
1229 unsafe fn to_napi_value(env: napi_ohos::bindgen_prelude::sys::napi_env, val: #name_with_lifetime) -> napi_ohos::bindgen_prelude::Result<napi_ohos::bindgen_prelude::sys::napi_value> {
1230 #[allow(unused_variables)]
1231 let env_wrapper = napi_ohos::bindgen_prelude::Env::from(env);
1232 #[allow(unused_mut)]
1233 let mut array = env_wrapper.create_array(#array_len)?;
1234
1235 let #destructed_fields = val;
1236 #(#obj_field_setters)*
1237
1238 napi_ohos::bindgen_prelude::Array::to_napi_value(env, array)
1239 }
1240 }
1241 }
1242 } else {
1243 quote! {}
1244 };
1245
1246 let from_napi_value = if array.object_from_js {
1247 let return_type = if self.has_lifetime {
1248 quote! { #name<'_javascript_function_scope> }
1249 } else {
1250 quote! { #name }
1251 };
1252 quote! {
1253 #[automatically_derived]
1254 #from_napi_value_impl {
1255 unsafe fn from_napi_value(
1256 env: napi_ohos::bindgen_prelude::sys::napi_env,
1257 napi_val: napi_ohos::bindgen_prelude::sys::napi_value
1258 ) -> napi_ohos::bindgen_prelude::Result<#return_type> {
1259 #[allow(unused_variables)]
1260 let env_wrapper = napi_ohos::bindgen_prelude::Env::from(env);
1261 #[allow(unused_mut)]
1262 let mut array = napi_ohos::bindgen_prelude::Array::from_napi_value(env, napi_val)?;
1263
1264 #(#obj_field_getters)*
1265
1266 let val = #destructed_fields;
1267
1268 Ok(val)
1269 }
1270 }
1271
1272 #[automatically_derived]
1273 #validate_napi_value_impl {}
1274 }
1275 } else {
1276 quote! {}
1277 };
1278
1279 quote! {
1280 #[automatically_derived]
1281 #type_name_impl {
1282 fn type_name() -> &'static str {
1283 #name_str
1284 }
1285
1286 fn value_type() -> napi_ohos::ValueType {
1287 napi_ohos::ValueType::Object
1288 }
1289 }
1290
1291 #to_napi_value
1292
1293 #from_napi_value
1294 }
1295 }
1296}
1297
1298impl TryToTokens for NapiImpl {
1299 fn try_to_tokens(&self, tokens: &mut TokenStream) -> BindgenResult<()> {
1300 self.gen_helper_mod()?.to_tokens(tokens);
1301
1302 Ok(())
1303 }
1304}
1305
1306impl NapiImpl {
1307 fn gen_helper_mod(&self) -> BindgenResult<TokenStream> {
1308 let name = &self.name;
1309 let name_str = self.name.to_string();
1310 let js_name = format!("{}\0", self.js_name);
1311 let mod_name = Ident::new(
1312 &format!(
1313 "__napi_impl_helper_{}_{}",
1314 name_str,
1315 NAPI_IMPL_ID.fetch_add(1, Ordering::SeqCst)
1316 ),
1317 Span::call_site(),
1318 );
1319
1320 let register_name = &self.register_name;
1321
1322 let mut methods = vec![];
1323 let mut props = HashMap::new();
1324
1325 for item in self.items.iter() {
1326 let js_name = Literal::string(&item.js_name);
1327 let item_str = item.name.to_string();
1328 let intermediate_name = get_intermediate_ident(&item_str);
1329 methods.push(item.try_to_token_stream()?);
1330
1331 let mut attribute = super::PROPERTY_ATTRIBUTE_DEFAULT;
1332 if item.writable {
1333 attribute |= super::PROPERTY_ATTRIBUTE_WRITABLE;
1334 }
1335 if item.enumerable {
1336 attribute |= super::PROPERTY_ATTRIBUTE_ENUMERABLE;
1337 }
1338 if item.configurable {
1339 attribute |= super::PROPERTY_ATTRIBUTE_CONFIGURABLE;
1340 }
1341
1342 let prop = props.entry(&item.js_name).or_insert_with(|| {
1343 quote! {
1344 napi_ohos::bindgen_prelude::Property::new().with_utf8_name(#js_name).unwrap().with_property_attributes(napi_ohos::bindgen_prelude::PropertyAttributes::from_bits(#attribute).unwrap())
1345 }
1346 });
1347
1348 let appendix = match item.kind {
1349 FnKind::Constructor => quote! { .with_ctor(#intermediate_name) },
1350 FnKind::Getter => quote! { .with_getter(#intermediate_name) },
1351 FnKind::Setter => quote! { .with_setter(#intermediate_name) },
1352 _ => {
1353 if item.fn_self.is_some() {
1354 quote! { .with_method(#intermediate_name) }
1355 } else {
1356 quote! { .with_method(#intermediate_name).with_property_attributes(napi_ohos::bindgen_prelude::PropertyAttributes::Static) }
1357 }
1358 }
1359 };
1360
1361 appendix.to_tokens(prop);
1362 }
1363
1364 let mut props: Vec<_> = props.into_iter().collect();
1365 props.sort_by_key(|(_, prop)| prop.to_string());
1366 let props = props.into_iter().map(|(_, prop)| prop);
1367 let props_wasm = props.clone();
1368 let js_mod_ident = js_mod_to_token_stream(self.js_mod.as_ref());
1369 Ok(quote! {
1370 #[allow(non_snake_case)]
1371 #[allow(clippy::all)]
1372 mod #mod_name {
1373 use super::*;
1374 #(#methods)*
1375
1376 #[cfg(all(not(test), not(target_family = "wasm")))]
1377 #[napi_ohos::ctor::ctor(crate_path=napi_ohos::ctor)]
1378 fn #register_name() {
1379 napi_ohos::__private::register_class(std::any::TypeId::of::<#name>(), #js_mod_ident, #js_name, vec![#(#props),*]);
1380 }
1381
1382 #[cfg(all(not(test), target_family = "wasm"))]
1383 #[no_mangle]
1384 extern "C" fn #register_name() {
1385 napi_ohos::__private::register_class(std::any::TypeId::of::<#name>(), #js_mod_ident, #js_name, vec![#(#props_wasm),*]);
1386 }
1387 }
1388 })
1389 }
1390}
1391
1392pub fn rm_raw_prefix(s: &str) -> &str {
1393 if let Some(stripped) = s.strip_prefix("r#") {
1394 stripped
1395 } else {
1396 s
1397 }
1398}
1399
1400fn remove_lifetime_in_type(ty: &mut syn::Type) {
1401 if let syn::Type::Path(syn::TypePath { path, .. }) = ty {
1402 path.segments.iter_mut().for_each(|segment| {
1403 if let syn::PathArguments::AngleBracketed(ref mut args) = segment.arguments {
1404 args.args.iter_mut().for_each(|arg| match arg {
1405 syn::GenericArgument::Type(ref mut ty) => {
1406 remove_lifetime_in_type(ty);
1407 }
1408 syn::GenericArgument::Lifetime(lifetime) => {
1409 lifetime.ident = Ident::new("_", lifetime.ident.span());
1410 }
1411 _ => {}
1412 });
1413 }
1414 });
1415 }
1416}