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};
6use crate::generators::{AdapterBodies, AsyncPattern, RustBindingConfig};
7use crate::shared::{constructor_parts, function_params, function_sig_defaults, partition_methods};
8use crate::type_mapper::TypeMapper;
9use ahash::AHashSet;
10use alef_core::ir::{MethodDef, TypeDef, TypeRef};
11use std::fmt::Write;
12
13pub fn is_trait_method_name(name: &str) -> bool {
16 crate::generators::TRAIT_METHOD_NAMES.contains(&name)
17}
18
19pub fn gen_constructor(typ: &TypeDef, mapper: &dyn TypeMapper, cfg: &RustBindingConfig) -> String {
21 let map_fn = |ty: &alef_core::ir::TypeRef| mapper.map_type(ty);
22
23 let (param_list, sig_defaults, assignments) = if typ.has_default {
25 crate::shared::config_constructor_parts_with_options(&typ.fields, &map_fn, cfg.option_duration_on_defaults)
26 } else {
27 constructor_parts(&typ.fields, &map_fn)
28 };
29
30 let mut out = String::with_capacity(512);
31 if typ.fields.len() > 7 {
33 writeln!(out, " #[allow(clippy::too_many_arguments)]").ok();
34 }
35 writeln!(out, " #[must_use]").ok();
36 if cfg.needs_signature {
37 writeln!(
38 out,
39 " {}{}{}",
40 cfg.signature_prefix, sig_defaults, cfg.signature_suffix
41 )
42 .ok();
43 }
44 write!(
45 out,
46 " {}\n pub fn new({param_list}) -> Self {{\n Self {{ {assignments} }}\n }}",
47 cfg.constructor_attr
48 )
49 .ok();
50 out
51}
52
53pub fn gen_method(
60 method: &MethodDef,
61 mapper: &dyn TypeMapper,
62 cfg: &RustBindingConfig,
63 typ: &TypeDef,
64 is_opaque: bool,
65 opaque_types: &AHashSet<String>,
66 adapter_bodies: &AdapterBodies,
67) -> String {
68 let type_name = &typ.name;
69 let core_type_path = typ.rust_path.replace('-', "_");
71
72 let map_fn = |ty: &alef_core::ir::TypeRef| mapper.map_type(ty);
73 let params = function_params(&method.params, &map_fn);
74 let return_type = mapper.map_type(&method.return_type);
75 let ret = mapper.wrap_return(&return_type, method.error_type.is_some());
76
77 let core_import = cfg.core_import;
78
79 let has_ref_named_params = method
82 .params
83 .iter()
84 .any(|p| p.is_ref && matches!(&p.ty, TypeRef::Named(n) if !opaque_types.contains(n.as_str())));
85 let (call_args, ref_let_bindings) = if has_ref_named_params {
86 (
87 gen_call_args_with_let_bindings(&method.params, opaque_types),
88 gen_named_let_bindings_pub(&method.params, opaque_types, core_import),
89 )
90 } else {
91 (gen_call_args(&method.params, opaque_types), String::new())
92 };
93
94 let is_owned_receiver = matches!(method.receiver.as_ref(), Some(alef_core::ir::ReceiverKind::Owned));
95 let is_ref_mut_receiver = matches!(method.receiver.as_ref(), Some(alef_core::ir::ReceiverKind::RefMut));
96
97 let is_functional_ref_mut = !is_opaque
104 && is_ref_mut_receiver
105 && !method.sanitized
106 && method.trait_source.is_none()
107 && method
108 .params
109 .iter()
110 .all(|p| !p.sanitized && crate::shared::is_delegatable_param(&p.ty, opaque_types));
111
112 let is_trait_method = method.trait_source.is_some();
115
116 let opaque_can_delegate = is_opaque
122 && !method.sanitized
123 && !is_ref_mut_receiver
124 && !is_trait_method
125 && (!is_owned_receiver || typ.is_clone)
126 && method
127 .params
128 .iter()
129 .all(|p| !p.sanitized && crate::shared::is_opaque_delegatable_type(&p.ty))
130 && crate::shared::is_opaque_delegatable_type(&method.return_type);
131
132 let make_core_call = |method_name: &str| -> String {
135 if is_opaque {
136 if is_owned_receiver {
137 format!("(*self.inner).clone().{method_name}({call_args})")
139 } else {
140 format!("self.inner.{method_name}({call_args})")
141 }
142 } else {
143 format!("{core_type_path}::from(self.clone()).{method_name}({call_args})")
144 }
145 };
146
147 let make_async_core_call = |method_name: &str| -> String {
149 if is_opaque {
150 format!("inner.{method_name}({call_args})")
151 } else {
152 format!("{core_type_path}::from(self.clone()).{method_name}({call_args})")
153 }
154 };
155
156 let result_expr = apply_return_newtype_unwrap("result", &method.return_newtype_wrapper);
163 let async_result_wrap = if is_opaque {
164 wrap_return(
165 &result_expr,
166 &method.return_type,
167 type_name,
168 opaque_types,
169 is_opaque,
170 method.returns_ref,
171 method.returns_cow,
172 )
173 } else {
174 match &method.return_type {
177 TypeRef::Named(_) | TypeRef::Json => format!("{result_expr}.into()"),
178 _ => result_expr.clone(),
179 }
180 };
181
182 let body = if !opaque_can_delegate {
183 let adapter_key = format!("{}.{}", type_name, method.name);
185 if let Some(adapter_body) = adapter_bodies.get(&adapter_key) {
186 adapter_body.clone()
187 } else if cfg.has_serde
188 && is_opaque
189 && !method.sanitized
190 && !is_trait_method
191 && has_named_params(&method.params, opaque_types)
192 && method.error_type.is_some()
193 && crate::shared::is_opaque_delegatable_type(&method.return_type)
194 {
195 let err_conv = match cfg.async_pattern {
198 AsyncPattern::Pyo3FutureIntoPy => {
199 ".map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))"
200 }
201 AsyncPattern::NapiNativeAsync => {
202 ".map_err(|e| napi::Error::new(napi::Status::GenericFailure, e.to_string()))"
203 }
204 AsyncPattern::WasmNativeAsync => ".map_err(|e| JsValue::from_str(&e.to_string()))",
205 _ => ".map_err(|e| e.to_string())",
206 };
207 let serde_bindings =
208 gen_serde_let_bindings(&method.params, opaque_types, cfg.core_import, err_conv, " ");
209 let serde_call_args = gen_call_args_with_let_bindings(&method.params, opaque_types);
210 let core_call = format!("self.inner.{}({serde_call_args})", method.name);
211 if matches!(method.return_type, TypeRef::Unit) {
212 format!("{serde_bindings}{core_call}{err_conv}?;\n Ok(())")
213 } else {
214 let wrap = wrap_return(
215 "result",
216 &method.return_type,
217 type_name,
218 opaque_types,
219 is_opaque,
220 method.returns_ref,
221 method.returns_cow,
222 );
223 format!("{serde_bindings}let result = {core_call}{err_conv}?;\n Ok({wrap})")
224 }
225 } else if is_functional_ref_mut {
226 let field_conversions =
235 gen_lossy_binding_to_core_fields_mut(typ, cfg.core_import, cfg.option_duration_on_defaults);
236 let core_call = format!("core_self.{}({call_args})", method.name);
237 if method.error_type.is_some() {
238 let err_conv = match cfg.async_pattern {
239 AsyncPattern::Pyo3FutureIntoPy => {
240 ".map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))"
241 }
242 AsyncPattern::NapiNativeAsync => {
243 ".map_err(|e| napi::Error::new(napi::Status::GenericFailure, e.to_string()))"
244 }
245 AsyncPattern::WasmNativeAsync => ".map_err(|e| JsValue::from_str(&e.to_string()))",
246 _ => ".map_err(|e| e.to_string())",
247 };
248 format!("{field_conversions}{core_call}{err_conv}?;\n Ok(core_self.into())")
249 } else {
250 format!("{field_conversions}{core_call};\n core_self.into()")
251 }
252 } else if !is_opaque
253 && !method.sanitized
254 && method
255 .params
256 .iter()
257 .all(|p| !p.sanitized && is_simple_non_opaque_param(&p.ty))
258 && crate::shared::is_delegatable_return(&method.return_type)
259 {
260 let is_ref_mut = matches!(method.receiver.as_ref(), Some(alef_core::ir::ReceiverKind::RefMut));
263 let field_conversions = if is_ref_mut {
264 gen_lossy_binding_to_core_fields_mut(typ, cfg.core_import, cfg.option_duration_on_defaults)
265 } else {
266 gen_lossy_binding_to_core_fields(typ, cfg.core_import, cfg.option_duration_on_defaults)
267 };
268 let core_call = format!("core_self.{}({call_args})", method.name);
269 let newtype_suffix = if method.return_newtype_wrapper.is_some() {
270 ".0"
271 } else {
272 ""
273 };
274 let result_wrap = match &method.return_type {
275 TypeRef::Named(n) if n == type_name && (method.returns_cow || method.returns_ref) => {
279 ".into_owned().into()".to_string()
280 }
281 TypeRef::Named(_) if method.returns_cow || method.returns_ref => ".into_owned().into()".to_string(),
282 TypeRef::Named(n) if n == type_name => ".into()".to_string(),
283 TypeRef::Named(_) => ".into()".to_string(),
284 TypeRef::String | TypeRef::Bytes | TypeRef::Path => {
285 if method.returns_ref {
286 ".to_owned()".to_string()
287 } else {
288 ".into()".to_string()
289 }
290 }
291 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Named(_)) => {
293 if method.returns_ref {
294 ".map(|v| v.clone().into())".to_string()
295 } else {
296 ".map(Into::into)".to_string()
297 }
298 }
299 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::String | TypeRef::Bytes) => {
301 if method.returns_ref {
302 ".map(|v| v.to_owned())".to_string()
303 } else {
304 String::new()
305 }
306 }
307 _ => String::new(),
308 };
309 if method.error_type.is_some() {
310 let err_conv = match cfg.async_pattern {
311 AsyncPattern::Pyo3FutureIntoPy => {
312 ".map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))"
313 }
314 AsyncPattern::NapiNativeAsync => {
315 ".map_err(|e| napi::Error::new(napi::Status::GenericFailure, e.to_string()))"
316 }
317 AsyncPattern::WasmNativeAsync => ".map_err(|e| JsValue::from_str(&e.to_string()))",
318 _ => ".map_err(|e| e.to_string())",
319 };
320 format!(
321 "{field_conversions}let result = {core_call}{err_conv}?;\n Ok(result{newtype_suffix}{result_wrap})"
322 )
323 } else {
324 format!("{field_conversions}{core_call}{newtype_suffix}{result_wrap}")
325 }
326 } else if is_opaque
327 && !method.sanitized
328 && !is_ref_mut_receiver
329 && (!is_owned_receiver || typ.is_clone)
330 && method.error_type.is_none()
331 && method
332 .params
333 .iter()
334 .all(|p| !p.sanitized && crate::shared::is_opaque_delegatable_type(&p.ty))
335 && matches!(&method.return_type, TypeRef::Named(n) if n == type_name)
336 {
337 let core_call = if is_owned_receiver {
340 format!("(*self.inner).clone().{}({call_args})", method.name)
341 } else {
342 format!("self.inner.{}({call_args})", method.name)
343 };
344 let unwrapped = apply_return_newtype_unwrap(&core_call, &method.return_newtype_wrapper);
345 format!("Self {{ inner: Arc::new({unwrapped}) }}")
346 } else if !is_opaque
347 && !method.sanitized
348 && !is_ref_mut_receiver
349 && (!is_owned_receiver || typ.is_clone)
350 && method.error_type.is_none()
351 && method
352 .params
353 .iter()
354 .all(|p| !p.sanitized && is_simple_non_opaque_param(&p.ty))
355 && matches!(&method.return_type, TypeRef::Named(n) if n == type_name)
356 {
357 let is_ref_mut = matches!(method.receiver.as_ref(), Some(alef_core::ir::ReceiverKind::RefMut));
360 let field_conversions = if is_ref_mut {
361 gen_lossy_binding_to_core_fields_mut(typ, cfg.core_import, cfg.option_duration_on_defaults)
362 } else {
363 gen_lossy_binding_to_core_fields(typ, cfg.core_import, cfg.option_duration_on_defaults)
364 };
365 let core_call = format!("core_self.{}({call_args})", method.name);
366 let newtype_suffix = if method.return_newtype_wrapper.is_some() {
367 ".0"
368 } else {
369 ""
370 };
371 let result_wrap = if method.returns_cow || method.returns_ref {
372 ".into_owned().into()"
373 } else {
374 ".into()"
375 };
376 format!("{field_conversions}{core_call}{newtype_suffix}{result_wrap}")
377 } else {
378 gen_unimplemented_body(
379 &method.return_type,
380 &format!("{type_name}.{}", method.name),
381 method.error_type.is_some(),
382 cfg,
383 &method.params,
384 )
385 }
386 } else if method.is_async {
387 let inner_clone_line = if is_opaque {
388 "let inner = self.inner.clone();\n "
389 } else {
390 ""
391 };
392 let core_call_str = make_async_core_call(&method.name);
393 gen_async_body(
394 &core_call_str,
395 cfg,
396 method.error_type.is_some(),
397 &async_result_wrap,
398 is_opaque,
399 inner_clone_line,
400 matches!(method.return_type, TypeRef::Unit),
401 Some(&return_type),
402 )
403 } else {
404 let core_call = make_core_call(&method.name);
405 if method.error_type.is_some() {
406 let err_conv = match cfg.async_pattern {
408 AsyncPattern::Pyo3FutureIntoPy => {
409 ".map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))"
410 }
411 AsyncPattern::NapiNativeAsync => {
412 ".map_err(|e| napi::Error::new(napi::Status::GenericFailure, e.to_string()))"
413 }
414 AsyncPattern::WasmNativeAsync => ".map_err(|e| JsValue::from_str(&e.to_string()))",
415 _ => ".map_err(|e| e.to_string())",
416 };
417 if is_opaque {
418 if matches!(method.return_type, TypeRef::Unit) {
419 format!("{core_call}{err_conv}?;\n Ok(())")
421 } else {
422 let wrap = wrap_return(
423 &result_expr,
424 &method.return_type,
425 type_name,
426 opaque_types,
427 is_opaque,
428 method.returns_ref,
429 method.returns_cow,
430 );
431 format!("let result = {core_call}{err_conv}?;\n Ok({wrap})")
432 }
433 } else {
434 format!("{core_call}{err_conv}")
435 }
436 } else if is_opaque {
437 let unwrapped_call = apply_return_newtype_unwrap(&core_call, &method.return_newtype_wrapper);
438 wrap_return(
439 &unwrapped_call,
440 &method.return_type,
441 type_name,
442 opaque_types,
443 is_opaque,
444 method.returns_ref,
445 method.returns_cow,
446 )
447 } else {
448 core_call
449 }
450 };
451 let body = if ref_let_bindings.is_empty() {
453 body
454 } else {
455 format!("{ref_let_bindings}{body}")
456 };
457
458 let needs_py = method.is_async && cfg.async_pattern == AsyncPattern::Pyo3FutureIntoPy;
459 let self_param = match (needs_py, params.is_empty()) {
460 (true, true) => "&self, py: Python<'py>",
461 (true, false) => "&self, py: Python<'py>, ",
462 (false, true) => "&self",
463 (false, false) => "&self, ",
464 };
465
466 let ret = if needs_py {
471 "PyResult<Bound<'py, PyAny>>".to_string()
472 } else if is_functional_ref_mut {
473 mapper.wrap_return("Self", method.error_type.is_some())
474 } else {
475 ret
476 };
477 let method_lifetime = if needs_py { "<'py>" } else { "" };
478
479 let (sig_start, sig_params, sig_end) = if self_param.len() + params.len() > 100 {
481 let wrapped_params = method
482 .params
483 .iter()
484 .map(|p| {
485 let ty = if p.optional {
486 format!("Option<{}>", mapper.map_type(&p.ty))
487 } else {
488 mapper.map_type(&p.ty)
489 };
490 format!("{}: {}", p.name, ty)
491 })
492 .collect::<Vec<_>>()
493 .join(",\n ");
494 let py_param = if needs_py { "\n py: Python<'py>," } else { "" };
495 (
496 format!(
497 "pub fn {}{method_lifetime}(\n &self,{}\n ",
498 method.name, py_param
499 ),
500 wrapped_params,
501 "\n ) -> ".to_string(),
502 )
503 } else {
504 (
505 format!("pub fn {}{method_lifetime}({}", method.name, self_param),
506 params,
507 ") -> ".to_string(),
508 )
509 };
510
511 let mut out = String::with_capacity(1024);
512 let total_params = method.params.len() + 1 + if needs_py { 1 } else { 0 };
514 if total_params > 7 {
515 writeln!(out, " #[allow(clippy::too_many_arguments)]").ok();
516 }
517 if method.error_type.is_some() {
519 writeln!(out, " #[allow(clippy::missing_errors_doc)]").ok();
520 }
521 if is_trait_method_name(&method.name) {
523 writeln!(out, " #[allow(clippy::should_implement_trait)]").ok();
524 }
525 if cfg.needs_signature {
526 let sig = function_sig_defaults(&method.params);
527 writeln!(out, " {}{}{}", cfg.signature_prefix, sig, cfg.signature_suffix).ok();
528 }
529 write!(
530 out,
531 " {}{}{}{} {{\n \
532 {body}\n }}",
533 sig_start, sig_params, sig_end, ret,
534 )
535 .ok();
536 out
537}
538
539pub fn gen_static_method(
541 method: &MethodDef,
542 mapper: &dyn TypeMapper,
543 cfg: &RustBindingConfig,
544 typ: &TypeDef,
545 adapter_bodies: &AdapterBodies,
546 opaque_types: &AHashSet<String>,
547) -> String {
548 let type_name = &typ.name;
549 let core_type_path = typ.rust_path.replace('-', "_");
551 let map_fn = |ty: &alef_core::ir::TypeRef| mapper.map_type(ty);
552 let params = function_params(&method.params, &map_fn);
553 let return_type = mapper.map_type(&method.return_type);
554 let ret = mapper.wrap_return(&return_type, method.error_type.is_some());
555
556 let core_import = cfg.core_import;
557
558 let use_let_bindings = has_named_params(&method.params, opaque_types);
561 let (call_args, ref_let_bindings) = if use_let_bindings {
562 (
563 gen_call_args_with_let_bindings(&method.params, opaque_types),
564 gen_named_let_bindings_pub(&method.params, opaque_types, core_import),
565 )
566 } else {
567 (gen_call_args(&method.params, opaque_types), String::new())
568 };
569
570 let can_delegate = crate::shared::can_auto_delegate(method, opaque_types);
571
572 let body = if !can_delegate {
573 let adapter_key = format!("{}.{}", type_name, method.name);
575 if let Some(adapter_body) = adapter_bodies.get(&adapter_key) {
576 adapter_body.clone()
577 } else {
578 gen_unimplemented_body(
579 &method.return_type,
580 &format!("{type_name}::{}", method.name),
581 method.error_type.is_some(),
582 cfg,
583 &method.params,
584 )
585 }
586 } else if method.is_async {
587 let core_call = format!("{core_type_path}::{}({call_args})", method.name);
588 let return_wrap = format!("{return_type}::from(result)");
589 gen_async_body(
590 &core_call,
591 cfg,
592 method.error_type.is_some(),
593 &return_wrap,
594 false,
595 "",
596 matches!(method.return_type, TypeRef::Unit),
597 Some(&return_type),
598 )
599 } else {
600 let core_call = format!("{core_type_path}::{}({call_args})", method.name);
601 if method.error_type.is_some() {
602 let err_conv = match cfg.async_pattern {
604 AsyncPattern::Pyo3FutureIntoPy => {
605 ".map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))"
606 }
607 AsyncPattern::NapiNativeAsync => {
608 ".map_err(|e| napi::Error::new(napi::Status::GenericFailure, e.to_string()))"
609 }
610 AsyncPattern::WasmNativeAsync => ".map_err(|e| JsValue::from_str(&e.to_string()))",
611 _ => ".map_err(|e| e.to_string())",
612 };
613 let val_expr = apply_return_newtype_unwrap("val", &method.return_newtype_wrapper);
615 let wrapped = wrap_return(
616 &val_expr,
617 &method.return_type,
618 type_name,
619 opaque_types,
620 typ.is_opaque,
621 method.returns_ref,
622 method.returns_cow,
623 );
624 if wrapped == val_expr {
625 format!("{core_call}{err_conv}")
626 } else {
627 format!("{core_call}.map(|val| {wrapped}){err_conv}")
628 }
629 } else {
630 let unwrapped_call = apply_return_newtype_unwrap(&core_call, &method.return_newtype_wrapper);
632 wrap_return(
633 &unwrapped_call,
634 &method.return_type,
635 type_name,
636 opaque_types,
637 typ.is_opaque,
638 method.returns_ref,
639 method.returns_cow,
640 )
641 }
642 };
643 let body = if ref_let_bindings.is_empty() {
645 body
646 } else {
647 format!("{ref_let_bindings}{body}")
648 };
649
650 let static_needs_py = method.is_async && cfg.async_pattern == AsyncPattern::Pyo3FutureIntoPy;
651
652 let ret = if static_needs_py {
654 "PyResult<Bound<'py, PyAny>>".to_string()
655 } else {
656 ret
657 };
658 let method_lifetime = if static_needs_py { "<'py>" } else { "" };
659
660 let (sig_start, sig_params, sig_end) = if params.len() > 100 {
662 let wrapped_params = method
663 .params
664 .iter()
665 .map(|p| {
666 let ty = if p.optional {
667 format!("Option<{}>", mapper.map_type(&p.ty))
668 } else {
669 mapper.map_type(&p.ty)
670 };
671 format!("{}: {}", p.name, ty)
672 })
673 .collect::<Vec<_>>()
674 .join(",\n ");
675 if static_needs_py {
677 (
678 format!("pub fn {}{method_lifetime}(py: Python<'py>,\n ", method.name),
679 wrapped_params,
680 "\n ) -> ".to_string(),
681 )
682 } else {
683 (
684 format!("pub fn {}(\n ", method.name),
685 wrapped_params,
686 "\n ) -> ".to_string(),
687 )
688 }
689 } else if static_needs_py {
690 (
691 format!("pub fn {}{method_lifetime}(py: Python<'py>, ", method.name),
692 params,
693 ") -> ".to_string(),
694 )
695 } else {
696 (format!("pub fn {}(", method.name), params, ") -> ".to_string())
697 };
698
699 let mut out = String::with_capacity(1024);
700 let total_params = method.params.len() + if static_needs_py { 1 } else { 0 };
702 if total_params > 7 {
703 writeln!(out, " #[allow(clippy::too_many_arguments)]").ok();
704 }
705 if method.error_type.is_some() {
707 writeln!(out, " #[allow(clippy::missing_errors_doc)]").ok();
708 }
709 if is_trait_method_name(&method.name) {
711 writeln!(out, " #[allow(clippy::should_implement_trait)]").ok();
712 }
713 if let Some(attr) = cfg.static_attr {
714 writeln!(out, " #[{attr}]").ok();
715 }
716 if cfg.needs_signature {
717 let sig = function_sig_defaults(&method.params);
718 writeln!(out, " {}{}{}", cfg.signature_prefix, sig, cfg.signature_suffix).ok();
719 }
720 write!(
721 out,
722 " {}{}{}{} {{\n \
723 {body}\n }}",
724 sig_start, sig_params, sig_end, ret,
725 )
726 .ok();
727 out
728}
729
730pub fn gen_impl_block(
732 typ: &TypeDef,
733 mapper: &dyn TypeMapper,
734 cfg: &RustBindingConfig,
735 adapter_bodies: &AdapterBodies,
736 opaque_types: &AHashSet<String>,
737) -> String {
738 let (instance, statics) = partition_methods(&typ.methods);
739 if instance.is_empty() && statics.is_empty() && typ.fields.is_empty() {
740 return String::new();
741 }
742
743 let prefixed_name = format!("{}{}", cfg.type_name_prefix, typ.name);
744 let mut out = String::with_capacity(2048);
745 if let Some(block_attr) = cfg.method_block_attr {
746 writeln!(out, "#[{block_attr}]").ok();
747 }
748 writeln!(out, "impl {prefixed_name} {{").ok();
749
750 if !typ.fields.is_empty() {
752 out.push_str(&gen_constructor(typ, mapper, cfg));
753 out.push_str("\n\n");
754 }
755
756 for m in &instance {
758 out.push_str(&gen_method(m, mapper, cfg, typ, false, opaque_types, adapter_bodies));
759 out.push_str("\n\n");
760 }
761
762 for m in &statics {
764 out.push_str(&gen_static_method(m, mapper, cfg, typ, adapter_bodies, opaque_types));
765 out.push_str("\n\n");
766 }
767
768 let trimmed = out.trim_end();
770 let mut result = trimmed.to_string();
771 result.push_str("\n}");
772 result
773}
774
775pub fn gen_opaque_impl_block(
780 typ: &TypeDef,
781 mapper: &dyn TypeMapper,
782 cfg: &RustBindingConfig,
783 opaque_types: &AHashSet<String>,
784 adapter_bodies: &AdapterBodies,
785) -> String {
786 let (instance, statics) = partition_methods(&typ.methods);
787 if instance.is_empty() && statics.is_empty() {
788 return String::new();
789 }
790
791 let mut out = String::with_capacity(2048);
792 let prefixed_name = format!("{}{}", cfg.type_name_prefix, typ.name);
793 if let Some(block_attr) = cfg.method_block_attr {
794 writeln!(out, "#[{block_attr}]").ok();
795 }
796 writeln!(out, "impl {prefixed_name} {{").ok();
797
798 for m in &instance {
800 out.push_str(&gen_method(m, mapper, cfg, typ, true, opaque_types, adapter_bodies));
801 out.push_str("\n\n");
802 }
803
804 for m in &statics {
806 out.push_str(&gen_static_method(m, mapper, cfg, typ, adapter_bodies, opaque_types));
807 out.push_str("\n\n");
808 }
809
810 let trimmed = out.trim_end();
811 let mut result = trimmed.to_string();
812 result.push_str("\n}");
813 result
814}