1use crate::generators::binding_helpers::{
2 apply_return_newtype_unwrap, gen_async_body, gen_call_args, gen_call_args_with_let_bindings,
3 gen_lossy_binding_to_core_fields, gen_lossy_binding_to_core_fields_mut, gen_named_let_bindings_pub,
4 gen_serde_let_bindings, gen_unimplemented_body, has_named_params, is_simple_non_opaque_param, wrap_return,
5 wrap_return_with_mutex,
6};
7use crate::generators::{AdapterBodies, AsyncPattern, RustBindingConfig};
8use crate::shared::{constructor_parts, function_params, function_sig_defaults, partition_methods};
9use crate::type_mapper::TypeMapper;
10use ahash::AHashSet;
11use alef_core::ir::{MethodDef, TypeDef, TypeRef};
12use std::fmt::Write;
13
14pub fn is_trait_method_name(name: &str) -> bool {
17 crate::generators::TRAIT_METHOD_NAMES.contains(&name)
18}
19
20pub fn gen_constructor(typ: &TypeDef, mapper: &dyn TypeMapper, cfg: &RustBindingConfig) -> String {
22 let map_fn = |ty: &alef_core::ir::TypeRef| mapper.map_type(ty);
23
24 let (param_list, sig_defaults, assignments) = if typ.has_default {
26 crate::shared::config_constructor_parts_with_options(&typ.fields, &map_fn, cfg.option_duration_on_defaults)
27 } else {
28 constructor_parts(&typ.fields, &map_fn)
29 };
30
31 let mut out = String::with_capacity(512);
32 if typ.fields.len() > 7 {
34 writeln!(out, " #[allow(clippy::too_many_arguments)]").ok();
35 }
36 writeln!(out, " #[must_use]").ok();
37 if cfg.needs_signature {
38 writeln!(
39 out,
40 " {}{}{}",
41 cfg.signature_prefix, sig_defaults, cfg.signature_suffix
42 )
43 .ok();
44 }
45 write!(
46 out,
47 " {}\n pub fn new({param_list}) -> Self {{\n Self {{ {assignments} }}\n }}",
48 cfg.constructor_attr
49 )
50 .ok();
51 out
52}
53
54#[allow(clippy::too_many_arguments)]
63pub fn gen_method(
64 method: &MethodDef,
65 mapper: &dyn TypeMapper,
66 cfg: &RustBindingConfig,
67 typ: &TypeDef,
68 is_opaque: bool,
69 opaque_types: &AHashSet<String>,
70 mutex_types: &AHashSet<String>,
71 adapter_bodies: &AdapterBodies,
72) -> String {
73 let type_name = &typ.name;
74 let core_type_path = typ.rust_path.replace('-', "_");
76
77 let map_fn = |ty: &alef_core::ir::TypeRef| mapper.map_type(ty);
78 let params = function_params(&method.params, &map_fn);
79 let return_type = mapper.map_type(&method.return_type);
80 let ret = mapper.wrap_return(&return_type, method.error_type.is_some());
81
82 let core_import = cfg.core_import;
83
84 let has_ref_named_params = has_named_params(&method.params, opaque_types);
88 let (call_args, ref_let_bindings) = if has_ref_named_params {
89 (
90 gen_call_args_with_let_bindings(&method.params, opaque_types),
91 gen_named_let_bindings_pub(&method.params, opaque_types, core_import),
92 )
93 } else {
94 (gen_call_args(&method.params, opaque_types), String::new())
95 };
96
97 let is_owned_receiver = matches!(method.receiver.as_ref(), Some(alef_core::ir::ReceiverKind::Owned));
98 let is_ref_mut_receiver = matches!(method.receiver.as_ref(), Some(alef_core::ir::ReceiverKind::RefMut));
99
100 let is_functional_ref_mut = !is_opaque
107 && is_ref_mut_receiver
108 && !method.sanitized
109 && method.trait_source.is_none()
110 && method
111 .params
112 .iter()
113 .all(|p| !p.sanitized && crate::shared::is_delegatable_param(&p.ty, opaque_types));
114
115 let is_trait_method = method.trait_source.is_some();
118
119 let self_needs_mutex = is_opaque && mutex_types.contains(type_name.as_str());
121
122 let opaque_can_delegate = is_opaque
129 && !method.sanitized
130 && (!is_ref_mut_receiver || self_needs_mutex)
131 && !is_trait_method
132 && (!is_owned_receiver || typ.is_clone)
133 && method
134 .params
135 .iter()
136 .all(|p| !p.sanitized && crate::shared::is_opaque_delegatable_type(&p.ty))
137 && crate::shared::is_opaque_delegatable_type(&method.return_type);
138
139 let make_core_call = |method_name: &str| -> String {
143 if is_opaque {
144 if is_owned_receiver {
145 if self_needs_mutex {
148 format!("self.inner.lock().unwrap().clone().{method_name}({call_args})")
149 } else {
150 format!("(*self.inner).clone().{method_name}({call_args})")
151 }
152 } else if self_needs_mutex {
153 format!("self.inner.lock().unwrap().{method_name}({call_args})")
155 } else {
156 format!("self.inner.{method_name}({call_args})")
157 }
158 } else {
159 format!("{core_type_path}::from(self.clone()).{method_name}({call_args})")
160 }
161 };
162
163 let make_async_core_call = |method_name: &str| -> String {
166 if is_opaque {
167 if self_needs_mutex {
168 format!("inner.lock().unwrap().{method_name}({call_args})")
169 } else {
170 format!("inner.{method_name}({call_args})")
171 }
172 } else {
173 format!("{core_type_path}::from(self.clone()).{method_name}({call_args})")
174 }
175 };
176
177 let result_expr = apply_return_newtype_unwrap("result", &method.return_newtype_wrapper);
184 let async_result_wrap = if is_opaque {
185 wrap_return_with_mutex(
186 &result_expr,
187 &method.return_type,
188 type_name,
189 opaque_types,
190 mutex_types,
191 is_opaque,
192 method.returns_ref,
193 method.returns_cow,
194 )
195 } else {
196 match &method.return_type {
199 TypeRef::Named(_) | TypeRef::Json => format!("{result_expr}.into()"),
200 _ => result_expr.clone(),
201 }
202 };
203
204 let body = if !opaque_can_delegate {
205 let adapter_key = format!("{}.{}", type_name, method.name);
207 if let Some(adapter_body) = adapter_bodies.get(&adapter_key) {
208 adapter_body.clone()
209 } else if cfg.has_serde
210 && is_opaque
211 && !method.sanitized
212 && !is_trait_method
213 && has_named_params(&method.params, opaque_types)
214 && method.error_type.is_some()
215 && crate::shared::is_opaque_delegatable_type(&method.return_type)
216 {
217 let err_conv = match cfg.async_pattern {
220 AsyncPattern::Pyo3FutureIntoPy => {
221 ".map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))"
222 }
223 AsyncPattern::NapiNativeAsync => {
224 ".map_err(|e| napi::Error::new(napi::Status::GenericFailure, e.to_string()))"
225 }
226 AsyncPattern::WasmNativeAsync => ".map_err(|e| JsValue::from_str(&e.to_string()))",
227 _ => ".map_err(|e| e.to_string())",
228 };
229 let serde_bindings =
230 gen_serde_let_bindings(&method.params, opaque_types, cfg.core_import, err_conv, " ");
231 let serde_call_args = gen_call_args_with_let_bindings(&method.params, opaque_types);
232 let core_call = if self_needs_mutex {
233 format!("self.inner.lock().unwrap().{}({serde_call_args})", method.name)
234 } else {
235 format!("self.inner.{}({serde_call_args})", method.name)
236 };
237 if matches!(method.return_type, TypeRef::Unit) {
238 format!("{serde_bindings}{core_call}{err_conv}?;\n Ok(())")
239 } else {
240 let wrap = wrap_return_with_mutex(
241 "result",
242 &method.return_type,
243 type_name,
244 opaque_types,
245 mutex_types,
246 is_opaque,
247 method.returns_ref,
248 method.returns_cow,
249 );
250 format!("{serde_bindings}let result = {core_call}{err_conv}?;\n Ok({wrap})")
251 }
252 } else if is_functional_ref_mut {
253 let field_conversions =
262 gen_lossy_binding_to_core_fields_mut(typ, cfg.core_import, cfg.option_duration_on_defaults);
263 let core_call = format!("core_self.{}({call_args})", method.name);
264 if method.error_type.is_some() {
265 let err_conv = match cfg.async_pattern {
266 AsyncPattern::Pyo3FutureIntoPy => {
267 ".map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))"
268 }
269 AsyncPattern::NapiNativeAsync => {
270 ".map_err(|e| napi::Error::new(napi::Status::GenericFailure, e.to_string()))"
271 }
272 AsyncPattern::WasmNativeAsync => ".map_err(|e| JsValue::from_str(&e.to_string()))",
273 _ => ".map_err(|e| e.to_string())",
274 };
275 format!("{field_conversions}{core_call}{err_conv}?;\n Ok(core_self.into())")
276 } else {
277 format!("{field_conversions}{core_call};\n core_self.into()")
278 }
279 } else if !is_opaque
280 && !method.sanitized
281 && method
282 .params
283 .iter()
284 .all(|p| !p.sanitized && is_simple_non_opaque_param(&p.ty))
285 && crate::shared::is_delegatable_return(&method.return_type)
286 {
287 let is_ref_mut = matches!(method.receiver.as_ref(), Some(alef_core::ir::ReceiverKind::RefMut));
290 let field_conversions = if is_ref_mut {
291 gen_lossy_binding_to_core_fields_mut(typ, cfg.core_import, cfg.option_duration_on_defaults)
292 } else {
293 gen_lossy_binding_to_core_fields(typ, cfg.core_import, cfg.option_duration_on_defaults)
294 };
295 let core_call = format!("core_self.{}({call_args})", method.name);
296 let newtype_suffix = if method.return_newtype_wrapper.is_some() {
297 ".0"
298 } else {
299 ""
300 };
301 let result_wrap = match &method.return_type {
302 TypeRef::Named(n) if n == type_name && (method.returns_cow || method.returns_ref) => {
306 ".into_owned().into()".to_string()
307 }
308 TypeRef::Named(_) if method.returns_cow || method.returns_ref => ".into_owned().into()".to_string(),
309 TypeRef::Named(n) if n == type_name => ".into()".to_string(),
310 TypeRef::Named(_) => ".into()".to_string(),
311 TypeRef::String | TypeRef::Bytes | TypeRef::Path => {
312 if method.returns_ref {
313 ".to_owned()".to_string()
314 } else {
315 ".into()".to_string()
316 }
317 }
318 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Named(_)) => {
320 if method.returns_ref {
321 ".map(|v| v.clone().into())".to_string()
322 } else {
323 ".map(Into::into)".to_string()
324 }
325 }
326 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::String | TypeRef::Bytes) => {
328 if method.returns_ref {
329 ".map(|v| v.to_owned())".to_string()
330 } else {
331 String::new()
332 }
333 }
334 _ => String::new(),
335 };
336 if method.error_type.is_some() {
337 let err_conv = match cfg.async_pattern {
338 AsyncPattern::Pyo3FutureIntoPy => {
339 ".map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))"
340 }
341 AsyncPattern::NapiNativeAsync => {
342 ".map_err(|e| napi::Error::new(napi::Status::GenericFailure, e.to_string()))"
343 }
344 AsyncPattern::WasmNativeAsync => ".map_err(|e| JsValue::from_str(&e.to_string()))",
345 _ => ".map_err(|e| e.to_string())",
346 };
347 format!(
348 "{field_conversions}let result = {core_call}{err_conv}?;\n Ok(result{newtype_suffix}{result_wrap})"
349 )
350 } else {
351 format!("{field_conversions}{core_call}{newtype_suffix}{result_wrap}")
352 }
353 } else if is_opaque
354 && !method.sanitized
355 && (!is_ref_mut_receiver || self_needs_mutex)
356 && (!is_owned_receiver || typ.is_clone)
357 && method.error_type.is_none()
358 && method
359 .params
360 .iter()
361 .all(|p| !p.sanitized && crate::shared::is_opaque_delegatable_type(&p.ty))
362 && matches!(&method.return_type, TypeRef::Named(n) if n == type_name)
363 {
364 let core_call = if is_owned_receiver {
367 if self_needs_mutex {
368 format!("self.inner.lock().unwrap().clone().{}({call_args})", method.name)
369 } else {
370 format!("(*self.inner).clone().{}({call_args})", method.name)
371 }
372 } else if self_needs_mutex {
373 format!("self.inner.lock().unwrap().{}({call_args})", method.name)
374 } else {
375 format!("self.inner.{}({call_args})", method.name)
376 };
377 let unwrapped = apply_return_newtype_unwrap(&core_call, &method.return_newtype_wrapper);
378 let arc_expr = if self_needs_mutex {
379 format!("Arc::new(std::sync::Mutex::new({unwrapped}))")
380 } else {
381 format!("Arc::new({unwrapped})")
382 };
383 format!("Self {{ inner: {arc_expr} }}")
384 } else if !is_opaque
385 && !method.sanitized
386 && !is_ref_mut_receiver
387 && (!is_owned_receiver || typ.is_clone)
388 && method.error_type.is_none()
389 && method
390 .params
391 .iter()
392 .all(|p| !p.sanitized && is_simple_non_opaque_param(&p.ty))
393 && matches!(&method.return_type, TypeRef::Named(n) if n == type_name)
394 {
395 let is_ref_mut = matches!(method.receiver.as_ref(), Some(alef_core::ir::ReceiverKind::RefMut));
398 let field_conversions = if is_ref_mut {
399 gen_lossy_binding_to_core_fields_mut(typ, cfg.core_import, cfg.option_duration_on_defaults)
400 } else {
401 gen_lossy_binding_to_core_fields(typ, cfg.core_import, cfg.option_duration_on_defaults)
402 };
403 let core_call = format!("core_self.{}({call_args})", method.name);
404 let newtype_suffix = if method.return_newtype_wrapper.is_some() {
405 ".0"
406 } else {
407 ""
408 };
409 let result_wrap = if method.returns_cow || method.returns_ref {
410 ".into_owned().into()"
411 } else {
412 ".into()"
413 };
414 format!("{field_conversions}{core_call}{newtype_suffix}{result_wrap}")
415 } else {
416 gen_unimplemented_body(
417 &method.return_type,
418 &format!("{type_name}.{}", method.name),
419 method.error_type.is_some(),
420 cfg,
421 &method.params,
422 opaque_types,
423 )
424 }
425 } else if method.is_async {
426 let inner_clone_line = if is_opaque {
427 "let inner = self.inner.clone();\n "
428 } else {
429 ""
430 };
431 let core_call_str = make_async_core_call(&method.name);
432 gen_async_body(
433 &core_call_str,
434 cfg,
435 method.error_type.is_some(),
436 &async_result_wrap,
437 is_opaque,
438 inner_clone_line,
439 matches!(method.return_type, TypeRef::Unit),
440 Some(&return_type),
441 )
442 } else {
443 let core_call = make_core_call(&method.name);
444 if method.error_type.is_some() {
445 let err_conv = match cfg.async_pattern {
447 AsyncPattern::Pyo3FutureIntoPy => {
448 ".map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))"
449 }
450 AsyncPattern::NapiNativeAsync => {
451 ".map_err(|e| napi::Error::new(napi::Status::GenericFailure, e.to_string()))"
452 }
453 AsyncPattern::WasmNativeAsync => ".map_err(|e| JsValue::from_str(&e.to_string()))",
454 _ => ".map_err(|e| e.to_string())",
455 };
456 if is_opaque {
457 if matches!(method.return_type, TypeRef::Unit) {
458 format!("{core_call}{err_conv}?;\n Ok(())")
460 } else {
461 let wrap = wrap_return_with_mutex(
462 &result_expr,
463 &method.return_type,
464 type_name,
465 opaque_types,
466 mutex_types,
467 is_opaque,
468 method.returns_ref,
469 method.returns_cow,
470 );
471 format!("let result = {core_call}{err_conv}?;\n Ok({wrap})")
472 }
473 } else {
474 format!("{core_call}{err_conv}")
475 }
476 } else if is_opaque {
477 let unwrapped_call = apply_return_newtype_unwrap(&core_call, &method.return_newtype_wrapper);
478 wrap_return_with_mutex(
479 &unwrapped_call,
480 &method.return_type,
481 type_name,
482 opaque_types,
483 mutex_types,
484 is_opaque,
485 method.returns_ref,
486 method.returns_cow,
487 )
488 } else {
489 core_call
490 }
491 };
492 let body = if ref_let_bindings.is_empty() {
494 body
495 } else {
496 format!("{ref_let_bindings}{body}")
497 };
498
499 let needs_py = method.is_async && cfg.async_pattern == AsyncPattern::Pyo3FutureIntoPy;
500 let self_param = match (needs_py, params.is_empty()) {
501 (true, true) => "&self, py: Python<'py>",
502 (true, false) => "&self, py: Python<'py>, ",
503 (false, true) => "&self",
504 (false, false) => "&self, ",
505 };
506
507 let ret = if needs_py {
512 "PyResult<Bound<'py, PyAny>>".to_string()
513 } else if is_functional_ref_mut {
514 mapper.wrap_return("Self", method.error_type.is_some())
515 } else {
516 ret
517 };
518 let method_lifetime = if needs_py { "<'py>" } else { "" };
519
520 let (sig_start, sig_params, sig_end) = if self_param.len() + params.len() > 100 {
522 let wrapped_params = method
523 .params
524 .iter()
525 .map(|p| {
526 let ty = if p.optional {
527 format!("Option<{}>", mapper.map_type(&p.ty))
528 } else {
529 mapper.map_type(&p.ty)
530 };
531 format!("{}: {}", p.name, ty)
532 })
533 .collect::<Vec<_>>()
534 .join(",\n ");
535 let py_param = if needs_py { "\n py: Python<'py>," } else { "" };
536 (
537 format!(
538 "pub fn {}{method_lifetime}(\n &self,{}\n ",
539 method.name, py_param
540 ),
541 wrapped_params,
542 "\n ) -> ".to_string(),
543 )
544 } else {
545 (
546 format!("pub fn {}{method_lifetime}({}", method.name, self_param),
547 params,
548 ") -> ".to_string(),
549 )
550 };
551
552 let mut out = String::with_capacity(1024);
553 let total_params = method.params.len() + 1 + if needs_py { 1 } else { 0 };
555 if total_params > 7 {
556 writeln!(out, " #[allow(clippy::too_many_arguments)]").ok();
557 }
558 if method.error_type.is_some() {
560 writeln!(out, " #[allow(clippy::missing_errors_doc)]").ok();
561 }
562 if is_trait_method_name(&method.name) {
564 writeln!(out, " #[allow(clippy::should_implement_trait)]").ok();
565 }
566 if cfg.needs_signature {
567 let sig = function_sig_defaults(&method.params);
568 writeln!(out, " {}{}{}", cfg.signature_prefix, sig, cfg.signature_suffix).ok();
569 }
570 write!(
571 out,
572 " {}{}{}{} {{\n \
573 {body}\n }}",
574 sig_start, sig_params, sig_end, ret,
575 )
576 .ok();
577 out
578}
579
580pub fn gen_static_method(
582 method: &MethodDef,
583 mapper: &dyn TypeMapper,
584 cfg: &RustBindingConfig,
585 typ: &TypeDef,
586 adapter_bodies: &AdapterBodies,
587 opaque_types: &AHashSet<String>,
588) -> String {
589 let type_name = &typ.name;
590 let core_type_path = typ.rust_path.replace('-', "_");
592 let map_fn = |ty: &alef_core::ir::TypeRef| mapper.map_type(ty);
593 let params = function_params(&method.params, &map_fn);
594 let return_type = mapper.map_type(&method.return_type);
595 let ret = mapper.wrap_return(&return_type, method.error_type.is_some());
596
597 let core_import = cfg.core_import;
598
599 let use_let_bindings = has_named_params(&method.params, opaque_types);
602 let (call_args, ref_let_bindings) = if use_let_bindings {
603 (
604 gen_call_args_with_let_bindings(&method.params, opaque_types),
605 gen_named_let_bindings_pub(&method.params, opaque_types, core_import),
606 )
607 } else {
608 (gen_call_args(&method.params, opaque_types), String::new())
609 };
610
611 let can_delegate = crate::shared::can_auto_delegate(method, opaque_types);
612
613 let body = if !can_delegate {
614 let adapter_key = format!("{}.{}", type_name, method.name);
616 if let Some(adapter_body) = adapter_bodies.get(&adapter_key) {
617 adapter_body.clone()
618 } else {
619 gen_unimplemented_body(
620 &method.return_type,
621 &format!("{type_name}::{}", method.name),
622 method.error_type.is_some(),
623 cfg,
624 &method.params,
625 opaque_types,
626 )
627 }
628 } else if method.is_async {
629 let core_call = format!("{core_type_path}::{}({call_args})", method.name);
630 let return_wrap = format!("{return_type}::from(result)");
631 gen_async_body(
632 &core_call,
633 cfg,
634 method.error_type.is_some(),
635 &return_wrap,
636 false,
637 "",
638 matches!(method.return_type, TypeRef::Unit),
639 Some(&return_type),
640 )
641 } else {
642 let core_call = format!("{core_type_path}::{}({call_args})", method.name);
643 if method.error_type.is_some() {
644 let err_conv = match cfg.async_pattern {
646 AsyncPattern::Pyo3FutureIntoPy => {
647 ".map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))"
648 }
649 AsyncPattern::NapiNativeAsync => {
650 ".map_err(|e| napi::Error::new(napi::Status::GenericFailure, e.to_string()))"
651 }
652 AsyncPattern::WasmNativeAsync => ".map_err(|e| JsValue::from_str(&e.to_string()))",
653 _ => ".map_err(|e| e.to_string())",
654 };
655 let val_expr = apply_return_newtype_unwrap("val", &method.return_newtype_wrapper);
657 let wrapped = wrap_return(
658 &val_expr,
659 &method.return_type,
660 type_name,
661 opaque_types,
662 typ.is_opaque,
663 method.returns_ref,
664 method.returns_cow,
665 );
666 if wrapped == val_expr {
667 format!("{core_call}{err_conv}")
668 } else {
669 format!("{core_call}.map(|val| {wrapped}){err_conv}")
670 }
671 } else {
672 let unwrapped_call = apply_return_newtype_unwrap(&core_call, &method.return_newtype_wrapper);
674 wrap_return(
675 &unwrapped_call,
676 &method.return_type,
677 type_name,
678 opaque_types,
679 typ.is_opaque,
680 method.returns_ref,
681 method.returns_cow,
682 )
683 }
684 };
685 let body = if ref_let_bindings.is_empty() {
687 body
688 } else {
689 format!("{ref_let_bindings}{body}")
690 };
691
692 let static_needs_py = method.is_async && cfg.async_pattern == AsyncPattern::Pyo3FutureIntoPy;
693
694 let ret = if static_needs_py {
696 "PyResult<Bound<'py, PyAny>>".to_string()
697 } else {
698 ret
699 };
700 let method_lifetime = if static_needs_py { "<'py>" } else { "" };
701
702 let (sig_start, sig_params, sig_end) = if params.len() > 100 {
704 let wrapped_params = method
705 .params
706 .iter()
707 .map(|p| {
708 let ty = if p.optional {
709 format!("Option<{}>", mapper.map_type(&p.ty))
710 } else {
711 mapper.map_type(&p.ty)
712 };
713 format!("{}: {}", p.name, ty)
714 })
715 .collect::<Vec<_>>()
716 .join(",\n ");
717 if static_needs_py {
719 (
720 format!("pub fn {}{method_lifetime}(py: Python<'py>,\n ", method.name),
721 wrapped_params,
722 "\n ) -> ".to_string(),
723 )
724 } else {
725 (
726 format!("pub fn {}(\n ", method.name),
727 wrapped_params,
728 "\n ) -> ".to_string(),
729 )
730 }
731 } else if static_needs_py {
732 (
733 format!("pub fn {}{method_lifetime}(py: Python<'py>, ", method.name),
734 params,
735 ") -> ".to_string(),
736 )
737 } else {
738 (format!("pub fn {}(", method.name), params, ") -> ".to_string())
739 };
740
741 let mut out = String::with_capacity(1024);
742 let total_params = method.params.len() + if static_needs_py { 1 } else { 0 };
744 if total_params > 7 {
745 writeln!(out, " #[allow(clippy::too_many_arguments)]").ok();
746 }
747 if method.error_type.is_some() {
749 writeln!(out, " #[allow(clippy::missing_errors_doc)]").ok();
750 }
751 if is_trait_method_name(&method.name) {
753 writeln!(out, " #[allow(clippy::should_implement_trait)]").ok();
754 }
755 if let Some(attr) = cfg.static_attr {
756 writeln!(out, " #[{attr}]").ok();
757 }
758 if cfg.needs_signature {
759 let sig = function_sig_defaults(&method.params);
760 writeln!(out, " {}{}{}", cfg.signature_prefix, sig, cfg.signature_suffix).ok();
761 }
762 write!(
763 out,
764 " {}{}{}{} {{\n \
765 {body}\n }}",
766 sig_start, sig_params, sig_end, ret,
767 )
768 .ok();
769 out
770}
771
772pub fn gen_impl_block(
774 typ: &TypeDef,
775 mapper: &dyn TypeMapper,
776 cfg: &RustBindingConfig,
777 adapter_bodies: &AdapterBodies,
778 opaque_types: &AHashSet<String>,
779) -> String {
780 let (instance, statics) = partition_methods(&typ.methods);
781 if instance.is_empty() && statics.is_empty() && typ.fields.is_empty() {
782 return String::new();
783 }
784
785 let prefixed_name = format!("{}{}", cfg.type_name_prefix, typ.name);
786 let mut out = String::with_capacity(2048);
787 if let Some(block_attr) = cfg.method_block_attr {
788 writeln!(out, "#[{block_attr}]").ok();
789 }
790 writeln!(out, "impl {prefixed_name} {{").ok();
791
792 if !typ.fields.is_empty() {
794 out.push_str(&gen_constructor(typ, mapper, cfg));
795 out.push_str("\n\n");
796 }
797
798 let empty_mutex_types: AHashSet<String> = AHashSet::new();
800 for m in &instance {
801 out.push_str(&gen_method(
802 m,
803 mapper,
804 cfg,
805 typ,
806 false,
807 opaque_types,
808 &empty_mutex_types,
809 adapter_bodies,
810 ));
811 out.push_str("\n\n");
812 }
813
814 for m in &statics {
816 out.push_str(&gen_static_method(m, mapper, cfg, typ, adapter_bodies, opaque_types));
817 out.push_str("\n\n");
818 }
819
820 let trimmed = out.trim_end();
822 let mut result = trimmed.to_string();
823 result.push_str("\n}");
824 result
825}
826
827pub fn gen_opaque_impl_block(
834 typ: &TypeDef,
835 mapper: &dyn TypeMapper,
836 cfg: &RustBindingConfig,
837 opaque_types: &AHashSet<String>,
838 mutex_types: &AHashSet<String>,
839 adapter_bodies: &AdapterBodies,
840) -> String {
841 let (instance, statics) = partition_methods(&typ.methods);
842 if instance.is_empty() && statics.is_empty() {
843 return String::new();
844 }
845
846 let mut out = String::with_capacity(2048);
847 let prefixed_name = format!("{}{}", cfg.type_name_prefix, typ.name);
848 if let Some(block_attr) = cfg.method_block_attr {
849 writeln!(out, "#[{block_attr}]").ok();
850 }
851 writeln!(out, "impl {prefixed_name} {{").ok();
852
853 for m in &instance {
855 out.push_str(&gen_method(
856 m,
857 mapper,
858 cfg,
859 typ,
860 true,
861 opaque_types,
862 mutex_types,
863 adapter_bodies,
864 ));
865 out.push_str("\n\n");
866 }
867
868 for m in &statics {
870 out.push_str(&gen_static_method(m, mapper, cfg, typ, adapter_bodies, opaque_types));
871 out.push_str("\n\n");
872 }
873
874 let trimmed = out.trim_end();
875 let mut result = trimmed.to_string();
876 result.push_str("\n}");
877 result
878}