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,
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_inner = format!("{}.{}", type_name, method.name);
207 if let Some(adapter_body) = adapter_bodies.get(&adapter_key_inner) {
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::Path => {
312 if method.returns_ref {
313 ".to_owned()".to_string()
314 } else {
315 ".into()".to_string()
316 }
317 }
318 TypeRef::Bytes => ".to_vec()".to_string(),
321 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Named(_)) => {
323 if method.returns_ref {
324 ".map(|v| v.clone().into())".to_string()
325 } else {
326 ".map(Into::into)".to_string()
327 }
328 }
329 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::String | TypeRef::Bytes) => {
331 if method.returns_ref {
332 ".map(|v| v.to_owned())".to_string()
333 } else {
334 String::new()
335 }
336 }
337 _ => String::new(),
338 };
339 if method.error_type.is_some() {
340 let err_conv = match cfg.async_pattern {
341 AsyncPattern::Pyo3FutureIntoPy => {
342 ".map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))"
343 }
344 AsyncPattern::NapiNativeAsync => {
345 ".map_err(|e| napi::Error::new(napi::Status::GenericFailure, e.to_string()))"
346 }
347 AsyncPattern::WasmNativeAsync => ".map_err(|e| JsValue::from_str(&e.to_string()))",
348 _ => ".map_err(|e| e.to_string())",
349 };
350 format!(
351 "{field_conversions}let result = {core_call}{err_conv}?;\n Ok(result{newtype_suffix}{result_wrap})"
352 )
353 } else {
354 format!("{field_conversions}{core_call}{newtype_suffix}{result_wrap}")
355 }
356 } else if is_opaque
357 && !method.sanitized
358 && (!is_ref_mut_receiver || self_needs_mutex)
359 && (!is_owned_receiver || typ.is_clone)
360 && method.error_type.is_none()
361 && method
362 .params
363 .iter()
364 .all(|p| !p.sanitized && crate::shared::is_opaque_delegatable_type(&p.ty))
365 && matches!(&method.return_type, TypeRef::Named(n) if n == type_name)
366 {
367 let core_call = if is_owned_receiver {
370 if self_needs_mutex {
371 format!("self.inner.lock().unwrap().clone().{}({call_args})", method.name)
372 } else {
373 format!("(*self.inner).clone().{}({call_args})", method.name)
374 }
375 } else if self_needs_mutex {
376 format!("self.inner.lock().unwrap().{}({call_args})", method.name)
377 } else {
378 format!("self.inner.{}({call_args})", method.name)
379 };
380 let unwrapped = apply_return_newtype_unwrap(&core_call, &method.return_newtype_wrapper);
381 let arc_expr = if self_needs_mutex {
382 format!("Arc::new(std::sync::Mutex::new({unwrapped}))")
383 } else {
384 format!("Arc::new({unwrapped})")
385 };
386 format!("Self {{ inner: {arc_expr} }}")
387 } else if !is_opaque
388 && !method.sanitized
389 && !is_ref_mut_receiver
390 && (!is_owned_receiver || typ.is_clone)
391 && method.error_type.is_none()
392 && method
393 .params
394 .iter()
395 .all(|p| !p.sanitized && is_simple_non_opaque_param(&p.ty))
396 && matches!(&method.return_type, TypeRef::Named(n) if n == type_name)
397 {
398 let is_ref_mut = matches!(method.receiver.as_ref(), Some(alef_core::ir::ReceiverKind::RefMut));
401 let field_conversions = if is_ref_mut {
402 gen_lossy_binding_to_core_fields_mut(typ, cfg.core_import, cfg.option_duration_on_defaults)
403 } else {
404 gen_lossy_binding_to_core_fields(typ, cfg.core_import, cfg.option_duration_on_defaults)
405 };
406 let core_call = format!("core_self.{}({call_args})", method.name);
407 let newtype_suffix = if method.return_newtype_wrapper.is_some() {
408 ".0"
409 } else {
410 ""
411 };
412 let result_wrap = if method.returns_cow || method.returns_ref {
413 ".into_owned().into()"
414 } else {
415 ".into()"
416 };
417 format!("{field_conversions}{core_call}{newtype_suffix}{result_wrap}")
418 } else {
419 gen_unimplemented_body(
420 &method.return_type,
421 &format!("{type_name}.{}", method.name),
422 method.error_type.is_some(),
423 cfg,
424 &method.params,
425 opaque_types,
426 )
427 }
428 } else if method.is_async {
429 let inner_clone_line = if is_opaque {
430 "let inner = self.inner.clone();\n "
431 } else {
432 ""
433 };
434 let core_call_str = make_async_core_call(&method.name);
435 gen_async_body(
436 &core_call_str,
437 cfg,
438 method.error_type.is_some(),
439 &async_result_wrap,
440 is_opaque,
441 inner_clone_line,
442 matches!(method.return_type, TypeRef::Unit),
443 Some(&return_type),
444 )
445 } else {
446 let core_call = make_core_call(&method.name);
447 if method.error_type.is_some() {
448 let err_conv = match cfg.async_pattern {
450 AsyncPattern::Pyo3FutureIntoPy => {
451 ".map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))"
452 }
453 AsyncPattern::NapiNativeAsync => {
454 ".map_err(|e| napi::Error::new(napi::Status::GenericFailure, e.to_string()))"
455 }
456 AsyncPattern::WasmNativeAsync => ".map_err(|e| JsValue::from_str(&e.to_string()))",
457 _ => ".map_err(|e| e.to_string())",
458 };
459 if is_opaque {
460 if matches!(method.return_type, TypeRef::Unit) {
461 format!("{core_call}{err_conv}?;\n Ok(())")
463 } else {
464 let wrap = wrap_return_with_mutex(
465 &result_expr,
466 &method.return_type,
467 type_name,
468 opaque_types,
469 mutex_types,
470 is_opaque,
471 method.returns_ref,
472 method.returns_cow,
473 );
474 format!("let result = {core_call}{err_conv}?;\n Ok({wrap})")
475 }
476 } else {
477 format!("{core_call}{err_conv}")
478 }
479 } else if is_opaque {
480 let unwrapped_call = apply_return_newtype_unwrap(&core_call, &method.return_newtype_wrapper);
481 wrap_return_with_mutex(
482 &unwrapped_call,
483 &method.return_type,
484 type_name,
485 opaque_types,
486 mutex_types,
487 is_opaque,
488 method.returns_ref,
489 method.returns_cow,
490 )
491 } else {
492 core_call
493 }
494 };
495 let adapter_key = format!("{}.{}", type_name, method.name);
496 let has_adapter = adapter_bodies.contains_key(&adapter_key);
497
498 let body = if ref_let_bindings.is_empty() || has_adapter {
504 body
505 } else {
506 format!("{ref_let_bindings}{body}")
507 };
508
509 let needs_py = method.is_async && cfg.async_pattern == AsyncPattern::Pyo3FutureIntoPy;
510
511 let body = if needs_py && !opaque_can_delegate && !has_adapter {
518 let err_msg = format!("Not implemented: {type_name}.{}", method.name);
519 let suppress = if method.params.is_empty() {
521 String::new()
522 } else {
523 let names: Vec<&str> = method.params.iter().map(|p| p.name.as_str()).collect();
524 if names.len() == 1 {
525 format!("let _ = {};\n ", names[0])
526 } else {
527 format!("let _ = ({});\n ", names.join(", "))
528 }
529 };
530 format!("{suppress}Err(pyo3::exceptions::PyNotImplementedError::new_err(\"{err_msg}\"))")
531 } else {
532 body
533 };
534 let self_param = match (needs_py, params.is_empty()) {
535 (true, true) => "&self, py: Python<'py>",
536 (true, false) => "&self, py: Python<'py>, ",
537 (false, true) => "&self",
538 (false, false) => "&self, ",
539 };
540
541 let ret = if needs_py {
546 "PyResult<Bound<'py, PyAny>>".to_string()
547 } else if is_functional_ref_mut {
548 mapper.wrap_return("Self", method.error_type.is_some())
549 } else {
550 ret
551 };
552 let method_lifetime = if needs_py { "<'py>" } else { "" };
553
554 let (sig_start, sig_params, sig_end) = if self_param.len() + params.len() > 100 {
556 let wrapped_params = method
557 .params
558 .iter()
559 .map(|p| {
560 let ty = if p.optional {
561 format!("Option<{}>", mapper.map_type(&p.ty))
562 } else {
563 mapper.map_type(&p.ty)
564 };
565 format!("{}: {}", p.name, ty)
566 })
567 .collect::<Vec<_>>()
568 .join(",\n ");
569 let py_param = if needs_py { "\n py: Python<'py>," } else { "" };
570 (
571 format!(
572 "pub fn {}{method_lifetime}(\n &self,{}\n ",
573 method.name, py_param
574 ),
575 wrapped_params,
576 "\n ) -> ".to_string(),
577 )
578 } else {
579 (
580 format!("pub fn {}{method_lifetime}({}", method.name, self_param),
581 params,
582 ") -> ".to_string(),
583 )
584 };
585
586 let mut out = String::with_capacity(1024);
587 let total_params = method.params.len() + 1 + if needs_py { 1 } else { 0 };
589 if total_params > 7 {
590 writeln!(out, " #[allow(clippy::too_many_arguments)]").ok();
591 }
592 if method.error_type.is_some() {
594 writeln!(out, " #[allow(clippy::missing_errors_doc)]").ok();
595 }
596 if is_trait_method_name(&method.name) {
598 writeln!(out, " #[allow(clippy::should_implement_trait)]").ok();
599 }
600 if cfg.needs_signature {
601 let sig = function_sig_defaults(&method.params);
602 writeln!(out, " {}{}{}", cfg.signature_prefix, sig, cfg.signature_suffix).ok();
603 }
604 write!(
605 out,
606 " {}{}{}{} {{\n \
607 {body}\n }}",
608 sig_start, sig_params, sig_end, ret,
609 )
610 .ok();
611 out
612}
613
614pub fn gen_static_method(
616 method: &MethodDef,
617 mapper: &dyn TypeMapper,
618 cfg: &RustBindingConfig,
619 typ: &TypeDef,
620 adapter_bodies: &AdapterBodies,
621 opaque_types: &AHashSet<String>,
622 mutex_types: &AHashSet<String>,
623) -> String {
624 let type_name = &typ.name;
625 let core_type_path = typ.rust_path.replace('-', "_");
627 let map_fn = |ty: &alef_core::ir::TypeRef| mapper.map_type(ty);
628 let params = function_params(&method.params, &map_fn);
629 let return_type = mapper.map_type(&method.return_type);
630 let ret = mapper.wrap_return(&return_type, method.error_type.is_some());
631
632 let core_import = cfg.core_import;
633
634 let use_let_bindings = has_named_params(&method.params, opaque_types);
637 let (call_args, ref_let_bindings) = if use_let_bindings {
638 (
639 gen_call_args_with_let_bindings(&method.params, opaque_types),
640 gen_named_let_bindings_pub(&method.params, opaque_types, core_import),
641 )
642 } else {
643 (gen_call_args(&method.params, opaque_types), String::new())
644 };
645
646 let can_delegate = crate::shared::can_auto_delegate(method, opaque_types);
647
648 let body = if !can_delegate {
649 let adapter_key = format!("{}.{}", type_name, method.name);
651 if let Some(adapter_body) = adapter_bodies.get(&adapter_key) {
652 adapter_body.clone()
653 } else {
654 gen_unimplemented_body(
655 &method.return_type,
656 &format!("{type_name}::{}", method.name),
657 method.error_type.is_some(),
658 cfg,
659 &method.params,
660 opaque_types,
661 )
662 }
663 } else if method.is_async {
664 let core_call = format!("{core_type_path}::{}({call_args})", method.name);
665 let return_wrap = format!("{return_type}::from(result)");
666 gen_async_body(
667 &core_call,
668 cfg,
669 method.error_type.is_some(),
670 &return_wrap,
671 false,
672 "",
673 matches!(method.return_type, TypeRef::Unit),
674 Some(&return_type),
675 )
676 } else {
677 let core_call = format!("{core_type_path}::{}({call_args})", method.name);
678 if method.error_type.is_some() {
679 let err_conv = match cfg.async_pattern {
681 AsyncPattern::Pyo3FutureIntoPy => {
682 ".map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))"
683 }
684 AsyncPattern::NapiNativeAsync => {
685 ".map_err(|e| napi::Error::new(napi::Status::GenericFailure, e.to_string()))"
686 }
687 AsyncPattern::WasmNativeAsync => ".map_err(|e| JsValue::from_str(&e.to_string()))",
688 _ => ".map_err(|e| e.to_string())",
689 };
690 let val_expr = apply_return_newtype_unwrap("val", &method.return_newtype_wrapper);
692 let wrapped = wrap_return_with_mutex(
693 &val_expr,
694 &method.return_type,
695 type_name,
696 opaque_types,
697 mutex_types,
698 typ.is_opaque,
699 method.returns_ref,
700 method.returns_cow,
701 );
702 if wrapped == val_expr {
703 format!("{core_call}{err_conv}")
704 } else {
705 format!("{core_call}.map(|val| {wrapped}){err_conv}")
706 }
707 } else {
708 let unwrapped_call = apply_return_newtype_unwrap(&core_call, &method.return_newtype_wrapper);
710 wrap_return_with_mutex(
711 &unwrapped_call,
712 &method.return_type,
713 type_name,
714 opaque_types,
715 mutex_types,
716 typ.is_opaque,
717 method.returns_ref,
718 method.returns_cow,
719 )
720 }
721 };
722 let body = if ref_let_bindings.is_empty() {
724 body
725 } else {
726 format!("{ref_let_bindings}{body}")
727 };
728
729 let static_needs_py = method.is_async && cfg.async_pattern == AsyncPattern::Pyo3FutureIntoPy;
730
731 let ret = if static_needs_py {
733 "PyResult<Bound<'py, PyAny>>".to_string()
734 } else {
735 ret
736 };
737 let method_lifetime = if static_needs_py { "<'py>" } else { "" };
738
739 let (sig_start, sig_params, sig_end) = if params.len() > 100 {
741 let wrapped_params = method
742 .params
743 .iter()
744 .map(|p| {
745 let ty = if p.optional {
746 format!("Option<{}>", mapper.map_type(&p.ty))
747 } else {
748 mapper.map_type(&p.ty)
749 };
750 format!("{}: {}", p.name, ty)
751 })
752 .collect::<Vec<_>>()
753 .join(",\n ");
754 if static_needs_py {
756 (
757 format!("pub fn {}{method_lifetime}(py: Python<'py>,\n ", method.name),
758 wrapped_params,
759 "\n ) -> ".to_string(),
760 )
761 } else {
762 (
763 format!("pub fn {}(\n ", method.name),
764 wrapped_params,
765 "\n ) -> ".to_string(),
766 )
767 }
768 } else if static_needs_py {
769 (
770 format!("pub fn {}{method_lifetime}(py: Python<'py>, ", method.name),
771 params,
772 ") -> ".to_string(),
773 )
774 } else {
775 (format!("pub fn {}(", method.name), params, ") -> ".to_string())
776 };
777
778 let mut out = String::with_capacity(1024);
779 let total_params = method.params.len() + if static_needs_py { 1 } else { 0 };
781 if total_params > 7 {
782 writeln!(out, " #[allow(clippy::too_many_arguments)]").ok();
783 }
784 if method.error_type.is_some() {
786 writeln!(out, " #[allow(clippy::missing_errors_doc)]").ok();
787 }
788 if is_trait_method_name(&method.name) {
790 writeln!(out, " #[allow(clippy::should_implement_trait)]").ok();
791 }
792 if let Some(attr) = cfg.static_attr {
793 writeln!(out, " #[{attr}]").ok();
794 }
795 if cfg.needs_signature {
796 let sig = function_sig_defaults(&method.params);
797 writeln!(out, " {}{}{}", cfg.signature_prefix, sig, cfg.signature_suffix).ok();
798 }
799 write!(
800 out,
801 " {}{}{}{} {{\n \
802 {body}\n }}",
803 sig_start, sig_params, sig_end, ret,
804 )
805 .ok();
806 out
807}
808
809pub fn gen_impl_block(
811 typ: &TypeDef,
812 mapper: &dyn TypeMapper,
813 cfg: &RustBindingConfig,
814 adapter_bodies: &AdapterBodies,
815 opaque_types: &AHashSet<String>,
816) -> String {
817 let (instance, statics) = partition_methods(&typ.methods);
818 let has_emittable_instance = instance
822 .iter()
823 .any(|m| !m.sanitized || adapter_bodies.contains_key(&format!("{}.{}", typ.name, m.name)));
824 let has_emittable_statics = statics
825 .iter()
826 .any(|m| !m.sanitized || adapter_bodies.contains_key(&format!("{}.{}", typ.name, m.name)));
827 if !has_emittable_instance && !has_emittable_statics && typ.fields.is_empty() {
828 return String::new();
829 }
830
831 let prefixed_name = format!("{}{}", cfg.type_name_prefix, typ.name);
832 let mut out = String::with_capacity(2048);
833 if let Some(block_attr) = cfg.method_block_attr {
834 writeln!(out, "#[{block_attr}]").ok();
835 }
836 writeln!(out, "impl {prefixed_name} {{").ok();
837
838 if !typ.fields.is_empty() {
840 out.push_str(&gen_constructor(typ, mapper, cfg));
841 out.push_str("\n\n");
842 }
843
844 let empty_mutex_types: AHashSet<String> = AHashSet::new();
846 for m in &instance {
847 let adapter_key = format!("{}.{}", typ.name, m.name);
851 if m.sanitized && !adapter_bodies.contains_key(&adapter_key) {
852 continue;
853 }
854 out.push_str(&gen_method(
855 m,
856 mapper,
857 cfg,
858 typ,
859 false,
860 opaque_types,
861 &empty_mutex_types,
862 adapter_bodies,
863 ));
864 out.push_str("\n\n");
865 }
866
867 for m in &statics {
869 let adapter_key = format!("{}.{}", typ.name, m.name);
871 if m.sanitized && !adapter_bodies.contains_key(&adapter_key) {
872 continue;
873 }
874 out.push_str(&gen_static_method(
875 m,
876 mapper,
877 cfg,
878 typ,
879 adapter_bodies,
880 opaque_types,
881 &empty_mutex_types,
882 ));
883 out.push_str("\n\n");
884 }
885
886 let trimmed = out.trim_end();
888 let mut result = trimmed.to_string();
889 result.push_str("\n}");
890 result
891}
892
893pub fn gen_opaque_impl_block(
900 typ: &TypeDef,
901 mapper: &dyn TypeMapper,
902 cfg: &RustBindingConfig,
903 opaque_types: &AHashSet<String>,
904 mutex_types: &AHashSet<String>,
905 adapter_bodies: &AdapterBodies,
906) -> String {
907 let (instance, statics) = partition_methods(&typ.methods);
908 let has_emittable_instance = instance
910 .iter()
911 .any(|m| !m.sanitized || adapter_bodies.contains_key(&format!("{}.{}", typ.name, m.name)));
912 let has_emittable_statics = statics
913 .iter()
914 .any(|m| !m.sanitized || adapter_bodies.contains_key(&format!("{}.{}", typ.name, m.name)));
915 if !has_emittable_instance && !has_emittable_statics {
916 return String::new();
917 }
918
919 let mut out = String::with_capacity(2048);
920 let prefixed_name = format!("{}{}", cfg.type_name_prefix, typ.name);
921 if let Some(block_attr) = cfg.method_block_attr {
922 writeln!(out, "#[{block_attr}]").ok();
923 }
924 writeln!(out, "impl {prefixed_name} {{").ok();
925
926 for m in &instance {
928 let adapter_key = format!("{}.{}", typ.name, m.name);
931 if m.sanitized && !adapter_bodies.contains_key(&adapter_key) {
932 continue;
933 }
934 out.push_str(&gen_method(
935 m,
936 mapper,
937 cfg,
938 typ,
939 true,
940 opaque_types,
941 mutex_types,
942 adapter_bodies,
943 ));
944 out.push_str("\n\n");
945 }
946
947 for m in &statics {
949 let adapter_key = format!("{}.{}", typ.name, m.name);
951 if m.sanitized && !adapter_bodies.contains_key(&adapter_key) {
952 continue;
953 }
954 out.push_str(&gen_static_method(
955 m,
956 mapper,
957 cfg,
958 typ,
959 adapter_bodies,
960 opaque_types,
961 mutex_types,
962 ));
963 out.push_str("\n\n");
964 }
965
966 let trimmed = out.trim_end();
967 let mut result = trimmed.to_string();
968 result.push_str("\n}");
969 result
970}