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
501 let body = if needs_py && !opaque_can_delegate {
507 let err_msg = format!("Not implemented: {type_name}.{}", method.name);
508 let suppress = if method.params.is_empty() {
511 String::new()
512 } else {
513 let names: Vec<&str> = method.params.iter().map(|p| p.name.as_str()).collect();
514 if names.len() == 1 {
515 format!("let _ = {};\n ", names[0])
516 } else {
517 format!("let _ = ({});\n ", names.join(", "))
518 }
519 };
520 format!(
521 "pyo3_async_runtimes::tokio::future_into_py(py, async move {{\n \
522 {suppress}Err(pyo3::exceptions::PyNotImplementedError::new_err(\"{err_msg}\"))\n \
523 }})"
524 )
525 } else {
526 body
527 };
528 let self_param = match (needs_py, params.is_empty()) {
529 (true, true) => "&self, py: Python<'py>",
530 (true, false) => "&self, py: Python<'py>, ",
531 (false, true) => "&self",
532 (false, false) => "&self, ",
533 };
534
535 let ret = if needs_py {
540 "PyResult<Bound<'py, PyAny>>".to_string()
541 } else if is_functional_ref_mut {
542 mapper.wrap_return("Self", method.error_type.is_some())
543 } else {
544 ret
545 };
546 let method_lifetime = if needs_py { "<'py>" } else { "" };
547
548 let (sig_start, sig_params, sig_end) = if self_param.len() + params.len() > 100 {
550 let wrapped_params = method
551 .params
552 .iter()
553 .map(|p| {
554 let ty = if p.optional {
555 format!("Option<{}>", mapper.map_type(&p.ty))
556 } else {
557 mapper.map_type(&p.ty)
558 };
559 format!("{}: {}", p.name, ty)
560 })
561 .collect::<Vec<_>>()
562 .join(",\n ");
563 let py_param = if needs_py { "\n py: Python<'py>," } else { "" };
564 (
565 format!(
566 "pub fn {}{method_lifetime}(\n &self,{}\n ",
567 method.name, py_param
568 ),
569 wrapped_params,
570 "\n ) -> ".to_string(),
571 )
572 } else {
573 (
574 format!("pub fn {}{method_lifetime}({}", method.name, self_param),
575 params,
576 ") -> ".to_string(),
577 )
578 };
579
580 let mut out = String::with_capacity(1024);
581 let total_params = method.params.len() + 1 + if needs_py { 1 } else { 0 };
583 if total_params > 7 {
584 writeln!(out, " #[allow(clippy::too_many_arguments)]").ok();
585 }
586 if method.error_type.is_some() {
588 writeln!(out, " #[allow(clippy::missing_errors_doc)]").ok();
589 }
590 if is_trait_method_name(&method.name) {
592 writeln!(out, " #[allow(clippy::should_implement_trait)]").ok();
593 }
594 if cfg.needs_signature {
595 let sig = function_sig_defaults(&method.params);
596 writeln!(out, " {}{}{}", cfg.signature_prefix, sig, cfg.signature_suffix).ok();
597 }
598 write!(
599 out,
600 " {}{}{}{} {{\n \
601 {body}\n }}",
602 sig_start, sig_params, sig_end, ret,
603 )
604 .ok();
605 out
606}
607
608pub fn gen_static_method(
610 method: &MethodDef,
611 mapper: &dyn TypeMapper,
612 cfg: &RustBindingConfig,
613 typ: &TypeDef,
614 adapter_bodies: &AdapterBodies,
615 opaque_types: &AHashSet<String>,
616) -> String {
617 let type_name = &typ.name;
618 let core_type_path = typ.rust_path.replace('-', "_");
620 let map_fn = |ty: &alef_core::ir::TypeRef| mapper.map_type(ty);
621 let params = function_params(&method.params, &map_fn);
622 let return_type = mapper.map_type(&method.return_type);
623 let ret = mapper.wrap_return(&return_type, method.error_type.is_some());
624
625 let core_import = cfg.core_import;
626
627 let use_let_bindings = has_named_params(&method.params, opaque_types);
630 let (call_args, ref_let_bindings) = if use_let_bindings {
631 (
632 gen_call_args_with_let_bindings(&method.params, opaque_types),
633 gen_named_let_bindings_pub(&method.params, opaque_types, core_import),
634 )
635 } else {
636 (gen_call_args(&method.params, opaque_types), String::new())
637 };
638
639 let can_delegate = crate::shared::can_auto_delegate(method, opaque_types);
640
641 let body = if !can_delegate {
642 let adapter_key = format!("{}.{}", type_name, method.name);
644 if let Some(adapter_body) = adapter_bodies.get(&adapter_key) {
645 adapter_body.clone()
646 } else {
647 gen_unimplemented_body(
648 &method.return_type,
649 &format!("{type_name}::{}", method.name),
650 method.error_type.is_some(),
651 cfg,
652 &method.params,
653 opaque_types,
654 )
655 }
656 } else if method.is_async {
657 let core_call = format!("{core_type_path}::{}({call_args})", method.name);
658 let return_wrap = format!("{return_type}::from(result)");
659 gen_async_body(
660 &core_call,
661 cfg,
662 method.error_type.is_some(),
663 &return_wrap,
664 false,
665 "",
666 matches!(method.return_type, TypeRef::Unit),
667 Some(&return_type),
668 )
669 } else {
670 let core_call = format!("{core_type_path}::{}({call_args})", method.name);
671 if method.error_type.is_some() {
672 let err_conv = match cfg.async_pattern {
674 AsyncPattern::Pyo3FutureIntoPy => {
675 ".map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))"
676 }
677 AsyncPattern::NapiNativeAsync => {
678 ".map_err(|e| napi::Error::new(napi::Status::GenericFailure, e.to_string()))"
679 }
680 AsyncPattern::WasmNativeAsync => ".map_err(|e| JsValue::from_str(&e.to_string()))",
681 _ => ".map_err(|e| e.to_string())",
682 };
683 let val_expr = apply_return_newtype_unwrap("val", &method.return_newtype_wrapper);
685 let wrapped = wrap_return(
686 &val_expr,
687 &method.return_type,
688 type_name,
689 opaque_types,
690 typ.is_opaque,
691 method.returns_ref,
692 method.returns_cow,
693 );
694 if wrapped == val_expr {
695 format!("{core_call}{err_conv}")
696 } else {
697 format!("{core_call}.map(|val| {wrapped}){err_conv}")
698 }
699 } else {
700 let unwrapped_call = apply_return_newtype_unwrap(&core_call, &method.return_newtype_wrapper);
702 wrap_return(
703 &unwrapped_call,
704 &method.return_type,
705 type_name,
706 opaque_types,
707 typ.is_opaque,
708 method.returns_ref,
709 method.returns_cow,
710 )
711 }
712 };
713 let body = if ref_let_bindings.is_empty() {
715 body
716 } else {
717 format!("{ref_let_bindings}{body}")
718 };
719
720 let static_needs_py = method.is_async && cfg.async_pattern == AsyncPattern::Pyo3FutureIntoPy;
721
722 let ret = if static_needs_py {
724 "PyResult<Bound<'py, PyAny>>".to_string()
725 } else {
726 ret
727 };
728 let method_lifetime = if static_needs_py { "<'py>" } else { "" };
729
730 let (sig_start, sig_params, sig_end) = if params.len() > 100 {
732 let wrapped_params = method
733 .params
734 .iter()
735 .map(|p| {
736 let ty = if p.optional {
737 format!("Option<{}>", mapper.map_type(&p.ty))
738 } else {
739 mapper.map_type(&p.ty)
740 };
741 format!("{}: {}", p.name, ty)
742 })
743 .collect::<Vec<_>>()
744 .join(",\n ");
745 if static_needs_py {
747 (
748 format!("pub fn {}{method_lifetime}(py: Python<'py>,\n ", method.name),
749 wrapped_params,
750 "\n ) -> ".to_string(),
751 )
752 } else {
753 (
754 format!("pub fn {}(\n ", method.name),
755 wrapped_params,
756 "\n ) -> ".to_string(),
757 )
758 }
759 } else if static_needs_py {
760 (
761 format!("pub fn {}{method_lifetime}(py: Python<'py>, ", method.name),
762 params,
763 ") -> ".to_string(),
764 )
765 } else {
766 (format!("pub fn {}(", method.name), params, ") -> ".to_string())
767 };
768
769 let mut out = String::with_capacity(1024);
770 let total_params = method.params.len() + if static_needs_py { 1 } else { 0 };
772 if total_params > 7 {
773 writeln!(out, " #[allow(clippy::too_many_arguments)]").ok();
774 }
775 if method.error_type.is_some() {
777 writeln!(out, " #[allow(clippy::missing_errors_doc)]").ok();
778 }
779 if is_trait_method_name(&method.name) {
781 writeln!(out, " #[allow(clippy::should_implement_trait)]").ok();
782 }
783 if let Some(attr) = cfg.static_attr {
784 writeln!(out, " #[{attr}]").ok();
785 }
786 if cfg.needs_signature {
787 let sig = function_sig_defaults(&method.params);
788 writeln!(out, " {}{}{}", cfg.signature_prefix, sig, cfg.signature_suffix).ok();
789 }
790 write!(
791 out,
792 " {}{}{}{} {{\n \
793 {body}\n }}",
794 sig_start, sig_params, sig_end, ret,
795 )
796 .ok();
797 out
798}
799
800pub fn gen_impl_block(
802 typ: &TypeDef,
803 mapper: &dyn TypeMapper,
804 cfg: &RustBindingConfig,
805 adapter_bodies: &AdapterBodies,
806 opaque_types: &AHashSet<String>,
807) -> String {
808 let (instance, statics) = partition_methods(&typ.methods);
809 if instance.is_empty() && statics.is_empty() && typ.fields.is_empty() {
810 return String::new();
811 }
812
813 let prefixed_name = format!("{}{}", cfg.type_name_prefix, typ.name);
814 let mut out = String::with_capacity(2048);
815 if let Some(block_attr) = cfg.method_block_attr {
816 writeln!(out, "#[{block_attr}]").ok();
817 }
818 writeln!(out, "impl {prefixed_name} {{").ok();
819
820 if !typ.fields.is_empty() {
822 out.push_str(&gen_constructor(typ, mapper, cfg));
823 out.push_str("\n\n");
824 }
825
826 let empty_mutex_types: AHashSet<String> = AHashSet::new();
828 for m in &instance {
829 out.push_str(&gen_method(
830 m,
831 mapper,
832 cfg,
833 typ,
834 false,
835 opaque_types,
836 &empty_mutex_types,
837 adapter_bodies,
838 ));
839 out.push_str("\n\n");
840 }
841
842 for m in &statics {
844 out.push_str(&gen_static_method(m, mapper, cfg, typ, adapter_bodies, opaque_types));
845 out.push_str("\n\n");
846 }
847
848 let trimmed = out.trim_end();
850 let mut result = trimmed.to_string();
851 result.push_str("\n}");
852 result
853}
854
855pub fn gen_opaque_impl_block(
862 typ: &TypeDef,
863 mapper: &dyn TypeMapper,
864 cfg: &RustBindingConfig,
865 opaque_types: &AHashSet<String>,
866 mutex_types: &AHashSet<String>,
867 adapter_bodies: &AdapterBodies,
868) -> String {
869 let (instance, statics) = partition_methods(&typ.methods);
870 if instance.is_empty() && statics.is_empty() {
871 return String::new();
872 }
873
874 let mut out = String::with_capacity(2048);
875 let prefixed_name = format!("{}{}", cfg.type_name_prefix, typ.name);
876 if let Some(block_attr) = cfg.method_block_attr {
877 writeln!(out, "#[{block_attr}]").ok();
878 }
879 writeln!(out, "impl {prefixed_name} {{").ok();
880
881 for m in &instance {
883 out.push_str(&gen_method(
884 m,
885 mapper,
886 cfg,
887 typ,
888 true,
889 opaque_types,
890 mutex_types,
891 adapter_bodies,
892 ));
893 out.push_str("\n\n");
894 }
895
896 for m in &statics {
898 out.push_str(&gen_static_method(m, mapper, cfg, typ, adapter_bodies, opaque_types));
899 out.push_str("\n\n");
900 }
901
902 let trimmed = out.trim_end();
903 let mut result = trimmed.to_string();
904 result.push_str("\n}");
905 result
906}