1use proc_macro2::{Ident, Span, TokenStream};
2use quote::ToTokens;
3use syn::{spanned::Spanned, Type, TypePath};
4
5use crate::{
6 codegen::{get_intermediate_ident, js_mod_to_token_stream},
7 BindgenResult, CallbackArg, Diagnostic, FnKind, FnSelf, NapiFn, NapiFnArgKind, TryToTokens,
8 TYPEDARRAY_SLICE_TYPES,
9};
10
11impl TryToTokens for NapiFn {
12 fn try_to_tokens(&self, tokens: &mut TokenStream) -> BindgenResult<()> {
13 let name_str = self.name.to_string();
14 let intermediate_ident = get_intermediate_ident(&name_str);
15 let args_len = self.args.len();
16
17 let ArgConversions {
18 arg_conversions,
19 args: arg_names,
20 refs,
21 mut_ref_spans,
22 unsafe_,
23 } = self.gen_arg_conversions()?;
24 if self.is_async && !mut_ref_spans.is_empty() && !unsafe_ {
27 return Diagnostic::from_vec(
28 mut_ref_spans
29 .into_iter()
30 .map(|s| Diagnostic::span_error(s, "mutable reference is unsafe with async"))
31 .collect(),
32 );
33 }
34 if Some(FnSelf::MutRef) == self.fn_self && self.is_async && !self.unsafe_ {
35 return Err(Diagnostic::span_error(
36 self.name.span(),
37 "&mut self in async napi methods should be marked as unsafe",
38 ));
39 }
40 let arg_ref_count = refs.len();
41 let receiver = self.gen_fn_receiver();
42 let receiver_ret_name = Ident::new("_ret", Span::call_site());
43 let ret = self.gen_fn_return(&receiver_ret_name)?;
44 let register = self.gen_fn_register();
45 let attrs = &self.attrs;
46
47 let build_ref_container = if self.is_async {
48 quote! {
49 struct NapiRefContainer([napi::sys::napi_ref; #arg_ref_count]);
50 impl NapiRefContainer {
51 fn drop(self, env: napi::sys::napi_env) {
52 for r in self.0.into_iter() {
53 assert_eq!(
54 unsafe { napi::sys::napi_reference_unref(env, r, &mut 0) },
55 napi::sys::Status::napi_ok,
56 "failed to delete napi ref"
57 );
58 assert_eq!(
59 unsafe { napi::sys::napi_delete_reference(env, r) },
60 napi::sys::Status::napi_ok,
61 "failed to delete napi ref"
62 );
63 }
64 }
65 }
66 unsafe impl Send for NapiRefContainer {}
67 unsafe impl Sync for NapiRefContainer {}
68 let _make_ref = |a: ::std::ptr::NonNull<napi::bindgen_prelude::sys::napi_value__>| {
69 let mut node_ref = ::std::mem::MaybeUninit::uninit();
70 napi::bindgen_prelude::check_status!(unsafe {
71 napi::bindgen_prelude::sys::napi_create_reference(env, a.as_ptr(), 1, node_ref.as_mut_ptr())
72 },
73 "failed to create napi ref"
74 )?;
75 Ok::<napi::sys::napi_ref, napi::Error>(unsafe { node_ref.assume_init() })
76 };
77 let mut _args_array = [::std::ptr::null_mut::<napi::bindgen_prelude::sys::napi_ref__>(); #arg_ref_count];
78 let mut _arg_write_index = 0;
79
80 #(#refs)*
81
82 #[cfg(debug_assertions)]
83 {
84 for a in &_args_array {
85 assert!(!a.is_null(), "failed to initialize napi ref");
86 }
87 }
88 let _args_ref = NapiRefContainer(_args_array);
89 }
90 } else {
91 quote! {}
92 };
93 let native_call = if !self.is_async {
94 if self.within_async_runtime {
95 quote! {
96 napi::bindgen_prelude::within_runtime_if_available(move || {
97 let #receiver_ret_name = {
98 #receiver(#(#arg_names),*)
99 };
100 #ret
101 })
102 }
103 } else {
104 quote! {
105 let #receiver_ret_name = {
106 #receiver(#(#arg_names),*)
107 };
108 #ret
109 }
110 }
111 } else {
112 let call = if self.is_ret_result {
113 quote! { #receiver(#(#arg_names),*).await }
114 } else {
115 let ret_type = if let Some(t) = &self.ret {
116 quote! { #t }
117 } else {
118 quote! { () }
119 };
120 quote! { Ok::<#ret_type, napi::Error>(#receiver(#(#arg_names),*).await) }
121 };
122 quote! {
123 napi::bindgen_prelude::execute_tokio_future(env, async move { #call }, move |env, #receiver_ret_name| {
124 _args_ref.drop(env);
125 #ret
126 })
127 }
128 };
129
130 let use_after_async = if self.is_async && self.parent.is_some() && self.fn_self.is_none() {
132 quote! { true }
133 } else {
134 quote! { false }
135 };
136
137 let function_call_inner = quote! {
138 napi::bindgen_prelude::CallbackInfo::<#args_len>::new(env, cb, None, #use_after_async).and_then(|#[allow(unused_mut)] mut cb| {
139 let __wrapped_env = napi::bindgen_prelude::Env::from(env);
140 #build_ref_container
141 #(#arg_conversions)*
142 #native_call
143 })
144 };
145
146 let function_call = if args_len == 0
147 && self.fn_self.is_none()
148 && self.kind != FnKind::Constructor
149 && self.kind != FnKind::Factory
150 && !self.is_async
151 {
152 quote! { #native_call }
153 } else if self.kind == FnKind::Constructor {
154 let return_from_factory = if self.catch_unwind {
155 quote! { return Ok(std::ptr::null_mut()); }
156 } else {
157 quote! { return std::ptr::null_mut(); }
158 };
159 quote! {
160 if napi::__private::___CALL_FROM_FACTORY.with(|inner| inner.load(std::sync::atomic::Ordering::Relaxed)) {
163 #return_from_factory
164 }
165 #function_call_inner
166 }
167 } else {
168 function_call_inner
169 };
170
171 let function_call = if self.catch_unwind {
172 quote! {
173 {
174 std::panic::catch_unwind(|| { #function_call })
175 .map_err(|e| {
176 let message = {
177 if let Some(string) = e.downcast_ref::<String>() {
178 string.clone()
179 } else if let Some(string) = e.downcast_ref::<&str>() {
180 string.to_string()
181 } else {
182 format!("panic from Rust code: {:?}", e)
183 }
184 };
185 napi::Error::new(napi::Status::GenericFailure, message)
186 })
187 .and_then(|r| r)
188 }
189 }
190 } else {
191 quote! {
192 #function_call
193 }
194 };
195
196 (quote! {
197 #(#attrs)*
198 #[doc(hidden)]
199 #[allow(non_snake_case)]
200 #[allow(clippy::all)]
201 extern "C" fn #intermediate_ident(
202 env: napi::bindgen_prelude::sys::napi_env,
203 cb: napi::bindgen_prelude::sys::napi_callback_info
204 ) -> napi::bindgen_prelude::sys::napi_value {
205 unsafe {
206 #function_call.unwrap_or_else(|e| {
207 napi::bindgen_prelude::JsError::from(e).throw_into(env);
208 std::ptr::null_mut::<napi::bindgen_prelude::sys::napi_value__>()
209 })
210 }
211 }
212
213 #register
214 })
215 .to_tokens(tokens);
216
217 Ok(())
218 }
219}
220
221impl NapiFn {
222 fn gen_arg_conversions(&self) -> BindgenResult<ArgConversions> {
223 let mut arg_conversions = vec![];
224 let mut args = vec![];
225 let mut refs = vec![];
226 let mut mut_ref_spans = vec![];
227 let make_ref = |input| {
228 quote! {
229 _args_array[_arg_write_index] = _make_ref(
230 ::std::ptr::NonNull::new(#input)
231 .ok_or_else(|| napi::Error::new(napi::Status::InvalidArg, "referenced ptr is null".to_owned()))?
232 )?;
233 _arg_write_index += 1;
234 }
235 };
236
237 if let Some(parent) = &self.parent {
239 match self.fn_self {
240 Some(FnSelf::Ref) => {
241 refs.push(make_ref(quote! { cb.this }));
242 arg_conversions.push(quote! {
243 let this_ptr = cb.unwrap_raw::<#parent>()?;
244 let this: &#parent = Box::leak(Box::from_raw(this_ptr));
245 });
246 }
247 Some(FnSelf::MutRef) => {
248 refs.push(make_ref(quote! { cb.this }));
249 arg_conversions.push(quote! {
250 let this_ptr = cb.unwrap_raw::<#parent>()?;
251 let this: &mut #parent = Box::leak(Box::from_raw(this_ptr));
252 });
253 }
254 _ => {}
255 };
256 }
257
258 let mut skipped_arg_count = 0;
259 for (i, arg) in self.args.iter().enumerate() {
260 let i = i - skipped_arg_count;
261 let ident = Ident::new(&format!("arg{}", i), Span::call_site());
262
263 match &arg.kind {
264 NapiFnArgKind::PatType(path) => {
265 if &path.ty.to_token_stream().to_string() == "Env" {
266 args.push(quote! { __wrapped_env });
267 skipped_arg_count += 1;
268 } else {
269 let is_in_class = self.parent.is_some();
270 if let syn::Type::Path(path) = path.ty.as_ref() {
271 if let Some(p) = path.path.segments.last() {
272 if p.ident == "Reference" {
273 if !is_in_class {
274 bail_span!(p, "`Reference` is only allowed in class methods");
275 }
276 if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
277 args: angle_bracketed_args,
278 ..
279 }) = &p.arguments
280 {
281 if let Some(syn::GenericArgument::Type(syn::Type::Path(path))) =
282 angle_bracketed_args.first()
283 {
284 if let Some(p) = path.path.segments.first() {
285 if p.ident == *self.parent.as_ref().unwrap() {
286 args.push(quote! {
287 napi::bindgen_prelude::Reference::from_value_ptr(this_ptr.cast(), env)?
288 });
289 skipped_arg_count += 1;
290 continue;
291 }
292 }
293 }
294 }
295 } else if p.ident == "This" {
296 if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
297 args: angle_bracketed_args,
298 ..
299 }) = &p.arguments
300 {
301 if let Some(syn::GenericArgument::Type(generic_type)) =
302 angle_bracketed_args.first()
303 {
304 if let syn::Type::Path(syn::TypePath {
305 path: syn::Path { segments, .. },
306 ..
307 }) = generic_type
308 {
309 if let Some(syn::PathSegment { ident, .. }) = segments.first() {
310 if let Some((primitive_type, _)) =
311 crate::PRIMITIVE_TYPES.iter().find(|(p, _)| ident == *p)
312 {
313 bail_span!(
314 ident,
315 "This type must not be {} \nthis in JavaScript function must be `Object` type or `undefined`",
316 primitive_type
317 );
318 }
319 args.push(
320 quote! {
321 {
322 <#ident as napi::bindgen_prelude::FromNapiValue>::from_napi_value(env, cb.this)?.into()
323 }
324 },
325 );
326 skipped_arg_count += 1;
327 continue;
328 }
329 } else if let syn::Type::Reference(syn::TypeReference {
330 elem,
331 mutability,
332 ..
333 }) = generic_type
334 {
335 if let syn::Type::Path(syn::TypePath {
336 path: syn::Path { segments, .. },
337 ..
338 }) = elem.as_ref()
339 {
340 if let Some(syn::PathSegment { ident, .. }) = segments.first() {
341 refs.push(make_ref(quote! { cb.this }));
342 let token = if mutability.is_some() {
343 mut_ref_spans.push(generic_type.span());
344 quote! { <#ident as napi::bindgen_prelude::FromNapiMutRef>::from_napi_mut_ref(env, cb.this)?.into() }
345 } else {
346 quote! { <#ident as napi::bindgen_prelude::FromNapiRef>::from_napi_ref(env, cb.this)?.into() }
347 };
348 args.push(token);
349 skipped_arg_count += 1;
350 continue;
351 }
352 }
353 }
354 }
355 }
356 refs.push(make_ref(quote! { cb.this }));
357 args.push(quote! { <napi::bindgen_prelude::This as napi::NapiValue>::from_raw_unchecked(env, cb.this) });
358 skipped_arg_count += 1;
359 continue;
360 }
361 }
362 }
363 let (arg_conversion, arg_type) = self.gen_ty_arg_conversion(&ident, i, path)?;
364 if NapiArgType::MutRef == arg_type {
365 mut_ref_spans.push(path.ty.span());
366 }
367 if arg_type.is_ref() {
368 refs.push(make_ref(quote! { cb.get_arg(#i) }));
369 }
370 if arg_type == NapiArgType::Env {
371 args.push(quote! { &__wrapped_env });
372 skipped_arg_count += 1;
373 continue;
374 }
375 arg_conversions.push(arg_conversion);
376 args.push(quote! { #ident });
377 }
378 }
379 NapiFnArgKind::Callback(cb) => {
380 arg_conversions.push(self.gen_cb_arg_conversion(&ident, i, cb)?);
381 args.push(quote! { #ident });
382 }
383 }
384 }
385
386 Ok(ArgConversions {
387 arg_conversions,
388 args,
389 refs,
390 mut_ref_spans,
391 unsafe_: self.unsafe_,
392 })
393 }
394
395 fn gen_ty_arg_conversion(
398 &self,
399 arg_name: &Ident,
400 index: usize,
401 path: &syn::PatType,
402 ) -> BindgenResult<(TokenStream, NapiArgType)> {
403 let mut ty = *path.ty.clone();
404 let type_check = if self.return_if_invalid {
405 quote! {
406 if let Ok(maybe_promise) = <#ty as napi::bindgen_prelude::ValidateNapiValue>::validate(env, cb.get_arg(#index)) {
407 if !maybe_promise.is_null() {
408 return Ok(maybe_promise);
409 }
410 } else {
411 return Ok(std::ptr::null_mut());
412 }
413 }
414 } else if self.strict {
415 quote! {
416 let maybe_promise = <#ty as napi::bindgen_prelude::ValidateNapiValue>::validate(env, cb.get_arg(#index))?;
417 if !maybe_promise.is_null() {
418 return Ok(maybe_promise);
419 }
420 }
421 } else {
422 quote! {}
423 };
424
425 match ty {
426 syn::Type::Reference(syn::TypeReference {
427 mutability: Some(_),
428 elem,
429 ..
430 }) => {
431 let q = quote! {
432 let #arg_name = {
433 #type_check
434 <#elem as napi::bindgen_prelude::FromNapiMutRef>::from_napi_mut_ref(env, cb.get_arg(#index))?
435 };
436 };
437 Ok((q, NapiArgType::MutRef))
438 }
439 syn::Type::Reference(syn::TypeReference {
440 mutability, elem, ..
441 }) => {
442 if let syn::Type::Slice(slice) = &*elem {
443 if let syn::Type::Path(ele) = &*slice.elem {
444 if let Some(syn::PathSegment { ident, .. }) = ele.path.segments.first() {
445 if TYPEDARRAY_SLICE_TYPES.contains_key(&&*ident.to_string()) {
446 let q = quote! {
447 let #arg_name = {
448 #type_check
449 <&mut #elem as napi::bindgen_prelude::FromNapiValue>::from_napi_value(env, cb.get_arg(#index))?
450 };
451 };
452 return Ok((q, NapiArgType::Ref));
453 }
454 }
455 }
456 }
457 let q = if mutability.is_some() {
458 quote! {
459 let #arg_name = {
460 #type_check
461 <#elem as napi::bindgen_prelude::FromNapiMutRef>::from_napi_mut_ref(env, cb.get_arg(#index))?
462 }
463 }
464 } else {
465 if let syn::Type::Path(ele) = &*elem {
466 if let Some(syn::PathSegment { ident, .. }) = ele.path.segments.last() {
467 if ident == "Env" {
468 return Ok((quote! {}, NapiArgType::Env));
469 } else if ident == "str" {
470 bail_span!(
471 elem,
472 "JavaScript String is primitive and cannot be passed by reference"
473 );
474 }
475 }
476 }
477 quote! {
478 let #arg_name = {
479 #type_check
480 <#elem as napi::bindgen_prelude::FromNapiRef>::from_napi_ref(env, cb.get_arg(#index))?
481 };
482 }
483 };
484 Ok((
485 q,
486 if mutability.is_some() {
487 NapiArgType::MutRef
488 } else {
489 NapiArgType::Ref
490 },
491 ))
492 }
493 _ => {
494 hidden_ty_lifetime(&mut ty)?;
495 let q = quote! {
496 let #arg_name = {
497 #type_check
498 <#ty as napi::bindgen_prelude::FromNapiValue>::from_napi_value(env, cb.get_arg(#index))?
499 };
500 };
501 Ok((q, NapiArgType::Value))
502 }
503 }
504 }
505
506 fn gen_cb_arg_conversion(
507 &self,
508 arg_name: &Ident,
509 index: usize,
510 cb: &CallbackArg,
511 ) -> BindgenResult<TokenStream> {
512 let mut inputs = vec![];
513 let mut arg_conversions = vec![];
514
515 for (i, ty) in cb.args.iter().enumerate() {
516 let cb_arg_ident = Ident::new(&format!("callback_arg_{}", i), Span::call_site());
517 inputs.push(quote! { #cb_arg_ident: #ty });
518 let mut maybe_has_lifetime_ty = ty.clone();
519 hidden_ty_lifetime(&mut maybe_has_lifetime_ty)?;
520 arg_conversions.push(
521 quote! { <#maybe_has_lifetime_ty as napi::bindgen_prelude::ToNapiValue>::to_napi_value(env, #cb_arg_ident)? },
522 );
523 }
524
525 let ret = match &cb.ret {
526 Some(ty) => {
527 quote! {
528 let ret = <#ty as napi::bindgen_prelude::FromNapiValue>::from_napi_value(env, ret_ptr)?;
529
530 Ok(ret)
531 }
532 }
533 None => quote! { Ok(()) },
534 };
535
536 Ok(quote! {
537 napi::bindgen_prelude::assert_type_of!(env, cb.get_arg(#index), napi::bindgen_prelude::ValueType::Function)?;
538 let #arg_name = |#(#inputs),*| {
539 let args = vec![
540 #(#arg_conversions),*
541 ];
542
543 let mut ret_ptr = std::ptr::null_mut();
544
545 napi::bindgen_prelude::check_pending_exception!(
546 env,
547 napi::bindgen_prelude::sys::napi_call_function(
548 env,
549 cb.this(),
550 cb.get_arg(#index),
551 args.len(),
552 args.as_ptr(),
553 &mut ret_ptr
554 )
555 )?;
556
557 #ret
558 };
559 })
560 }
561
562 fn gen_fn_receiver(&self) -> TokenStream {
563 let name = &self.name;
564
565 match self.fn_self {
566 Some(FnSelf::Value) => {
567 unreachable!();
569 }
570 Some(FnSelf::Ref) | Some(FnSelf::MutRef) => quote! { this.#name },
571 None => match &self.parent {
572 Some(class) => quote! { #class::#name },
573 None => quote! { #name },
574 },
575 }
576 }
577
578 fn gen_fn_return(&self, ret: &Ident) -> BindgenResult<TokenStream> {
579 let js_name = &self.js_name;
580
581 if let Some(ty) = &self.ret {
582 let ty_string = ty.into_token_stream().to_string();
583 let is_return_self = ty_string == "& Self" || ty_string == "&mut Self";
584 if self.kind == FnKind::Constructor {
585 let parent = self
586 .parent
587 .as_ref()
588 .expect("Parent must exist for constructor");
589 if self.is_ret_result {
590 if self.parent_is_generator {
591 Ok(quote! { cb.construct_generator::<false, _>(#js_name, #ret?) })
592 } else {
593 Ok(quote! {
594 match #ret {
595 Ok(value) => {
596 cb.construct::<false, _>(#js_name, value)
597 }
598 Err(err) => {
599 napi::bindgen_prelude::JsError::from(err).throw_into(env);
600 Ok(std::ptr::null_mut())
601 }
602 }
603 })
604 }
605 } else if self.parent_is_generator {
606 Ok(quote! { cb.construct_generator::<false, #parent>(#js_name, #ret) })
607 } else {
608 Ok(quote! { cb.construct::<false, #parent>(#js_name, #ret) })
609 }
610 } else if self.kind == FnKind::Factory {
611 if self.is_ret_result {
612 if self.parent_is_generator {
613 Ok(quote! { cb.generator_factory(#js_name, #ret?) })
614 } else if self.is_async {
615 Ok(quote! { cb.factory(#js_name, #ret) })
616 } else {
617 Ok(quote! {
618 match #ret {
619 Ok(value) => {
620 cb.factory(#js_name, value)
621 }
622 Err(err) => {
623 napi::bindgen_prelude::JsError::from(err).throw_into(env);
624 Ok(std::ptr::null_mut())
625 }
626 }
627 })
628 }
629 } else if self.parent_is_generator {
630 Ok(quote! { cb.generator_factory(#js_name, #ret) })
631 } else {
632 Ok(quote! { cb.factory(#js_name, #ret) })
633 }
634 } else if self.is_ret_result {
635 if self.is_async {
636 Ok(quote! {
637 <#ty as napi::bindgen_prelude::ToNapiValue>::to_napi_value(env, #ret)
638 })
639 } else if is_return_self {
640 Ok(quote! { #ret.map(|_| cb.this) })
641 } else {
642 Ok(quote! {
643 match #ret {
644 Ok(value) => napi::bindgen_prelude::ToNapiValue::to_napi_value(env, value),
645 Err(err) => {
646 napi::bindgen_prelude::JsError::from(err).throw_into(env);
647 Ok(std::ptr::null_mut())
648 },
649 }
650 })
651 }
652 } else if is_return_self {
653 Ok(quote! { Ok(cb.this) })
654 } else {
655 let mut return_ty = ty.clone();
656 hidden_ty_lifetime(&mut return_ty)?;
657 Ok(quote! {
658 <#return_ty as napi::bindgen_prelude::ToNapiValue>::to_napi_value(env, #ret)
659 })
660 }
661 } else {
662 Ok(quote! {
663 <() as napi::bindgen_prelude::ToNapiValue>::to_napi_value(env, ())
664 })
665 }
666 }
667
668 fn gen_fn_register(&self) -> TokenStream {
669 if self.parent.is_some() {
670 quote! {}
671 } else {
672 let name_str = self.name.to_string();
673 let js_name = format!("{}\0", &self.js_name);
674 let name_len = self.js_name.len();
675 let module_register_name = &self.register_name;
676 let intermediate_ident = get_intermediate_ident(&name_str);
677 let js_mod_ident = js_mod_to_token_stream(self.js_mod.as_ref());
678 let cb_name = Ident::new(&format!("{}_js_function", name_str), Span::call_site());
679
680 quote! {
681 #[allow(non_snake_case)]
682 #[allow(clippy::all)]
683 unsafe fn #cb_name(env: napi::bindgen_prelude::sys::napi_env) -> napi::bindgen_prelude::Result<napi::bindgen_prelude::sys::napi_value> {
684 let mut fn_ptr = std::ptr::null_mut();
685
686 napi::bindgen_prelude::check_status!(
687 napi::bindgen_prelude::sys::napi_create_function(
688 env,
689 #js_name.as_ptr().cast(),
690 #name_len as isize,
691 Some(#intermediate_ident),
692 std::ptr::null_mut(),
693 &mut fn_ptr,
694 ),
695 "Failed to register function `{}`",
696 #name_str,
697 )?;
698 napi::bindgen_prelude::register_js_function(#js_name, #cb_name, Some(#intermediate_ident));
699 Ok(fn_ptr)
700 }
701
702 #[allow(clippy::all)]
703 #[allow(non_snake_case)]
704 #[cfg(all(not(test), not(target_family = "wasm")))]
705 #[napi::ctor::ctor(crate_path=::napi::ctor)]
706 fn #module_register_name() {
707 napi::bindgen_prelude::register_module_export(#js_mod_ident, #js_name, #cb_name);
708 }
709
710 #[allow(clippy::all)]
711 #[allow(non_snake_case)]
712 #[cfg(all(not(test), target_family = "wasm"))]
713 #[no_mangle]
714 extern "C" fn #module_register_name() {
715 napi::bindgen_prelude::register_module_export(#js_mod_ident, #js_name, #cb_name);
716 }
717 }
718 }
719 }
720}
721
722fn hidden_ty_lifetime(ty: &mut syn::Type) -> BindgenResult<()> {
723 if let Type::Path(TypePath {
724 path: syn::Path { segments, .. },
725 ..
726 }) = ty
727 {
728 if let Some(syn::PathSegment {
729 arguments:
730 syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { args, .. }),
731 ..
732 }) = segments.last_mut()
733 {
734 if let Some(syn::GenericArgument::Lifetime(lt)) = args.first_mut() {
735 *lt = syn::Lifetime::new("'_", Span::call_site());
736 }
737 for arg in args.iter_mut().skip(1) {
738 if let syn::GenericArgument::Type(ty) = arg {
739 hidden_ty_lifetime(ty)?;
740 }
741 }
742 }
743 }
744 Ok(())
745}
746
747struct ArgConversions {
748 pub args: Vec<TokenStream>,
749 pub arg_conversions: Vec<TokenStream>,
750 pub refs: Vec<TokenStream>,
751 pub mut_ref_spans: Vec<Span>,
752 pub unsafe_: bool,
753}
754
755#[derive(Debug, PartialEq, Eq)]
756enum NapiArgType {
757 Ref,
758 MutRef,
759 Value,
760 Env,
761}
762
763impl NapiArgType {
764 fn is_ref(&self) -> bool {
765 matches!(self, NapiArgType::Ref | NapiArgType::MutRef)
766 }
767}