1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use crate::core::ir::MethodDef;
use super::{
TraitBridgeSpec, gen_bridge_clear_fn, gen_bridge_debug_impl, gen_bridge_plugin_impl, gen_bridge_registration_fn,
gen_bridge_trait_impl, gen_bridge_unregistration_fn, gen_bridge_wrapper_struct,
};
pub trait TraitBridgeGenerator {
/// The type of the wrapped foreign object (e.g., `"Py<PyAny>"`, `"ThreadsafeFunction"`).
fn foreign_object_type(&self) -> &str;
/// Additional `use` imports needed for the bridge code.
fn bridge_imports(&self) -> Vec<String>;
/// Generate the body of a synchronous method bridge.
///
/// The returned string is inserted inside the trait impl method. It should
/// call through to the foreign object and convert the result.
fn gen_sync_method_body(&self, method: &MethodDef, spec: &TraitBridgeSpec) -> String;
/// Generate the body of an async method bridge.
///
/// The returned string is the body of a `Box::pin(async move { ... })` block.
fn gen_async_method_body(&self, method: &MethodDef, spec: &TraitBridgeSpec) -> String;
/// Generate the constructor body that validates and wraps the foreign object.
///
/// Should check that the foreign object provides all required methods and
/// return `Self { ... }` on success.
fn gen_constructor(&self, spec: &TraitBridgeSpec) -> String;
/// Generate the complete registration function including attributes, signature, and body.
///
/// Each backend needs different function signatures (PyO3 takes `py: Python`,
/// NAPI takes `#[napi]` with JS params, FFI takes `extern "C"` with raw pointers),
/// so the generator owns the full function.
fn gen_registration_fn(&self, spec: &TraitBridgeSpec) -> String;
/// Generate an unregistration function for the bridge.
///
/// Default implementation returns an empty string — backends opt in by
/// emitting a function whose name is `spec.bridge_config.unregister_fn`
/// (when set) and whose body calls into the host crate's
/// `unregister_*(name)` plugin entry point.
fn gen_unregistration_fn(&self, _spec: &TraitBridgeSpec) -> String {
String::new()
}
/// Generate a clear-all-plugins function for the bridge.
///
/// Default implementation returns an empty string — backends opt in by
/// emitting a function whose name is `spec.bridge_config.clear_fn`
/// (when set) and whose body calls into the host crate's `clear_*()`
/// plugin entry point. Typically used in test teardown.
fn gen_clear_fn(&self, _spec: &TraitBridgeSpec) -> String {
String::new()
}
/// Whether the `#[async_trait]` macro should require `Send` on its futures.
///
/// Returns `true` (default) for most targets. WASM is single-threaded so its
/// trait bounds don't include `Send`; implementors should return `false` there.
fn async_trait_is_send(&self) -> bool {
true
}
}
pub struct BridgeOutput {
/// Import paths (e.g., `"std::sync::Arc"`) — callers should add via `builder.add_import()`.
pub imports: Vec<String>,
/// The generated code (struct, impls, registration fn).
pub code: String,
}
/// Generate the complete trait bridge code block: struct, impls, and
/// optionally a registration function.
///
/// Returns [`BridgeOutput`] with imports separated from code so callers can
/// route imports through `builder.add_import()` (which deduplicates).
pub fn gen_bridge_all(spec: &TraitBridgeSpec, generator: &dyn TraitBridgeGenerator) -> BridgeOutput {
let imports = generator.bridge_imports();
let mut out = String::with_capacity(4096);
// Wrapper struct
out.push_str(&gen_bridge_wrapper_struct(spec, generator));
out.push_str("\n\n");
// Debug impl (required by Plugin super-trait Debug bound)
out.push_str(&gen_bridge_debug_impl(spec));
out.push_str("\n\n");
// Constructor (impl block with new())
out.push_str(&generator.gen_constructor(spec));
out.push_str("\n\n");
// Plugin super-trait impl (if applicable)
if let Some(plugin_impl) = gen_bridge_plugin_impl(spec, generator) {
out.push_str(&plugin_impl);
out.push_str("\n\n");
}
// Trait impl
out.push_str(&gen_bridge_trait_impl(spec, generator));
// Registration function — only when register_fn is configured
if let Some(reg_fn_code) = gen_bridge_registration_fn(spec, generator) {
out.push_str("\n\n");
out.push_str(®_fn_code);
}
// Unregistration function — only when unregister_fn is configured AND
// the backend has opted in (non-empty body).
if let Some(unreg_fn_code) = gen_bridge_unregistration_fn(spec, generator) {
out.push_str("\n\n");
out.push_str(&unreg_fn_code);
}
// Clear-all function — only when clear_fn is configured AND the backend
// has opted in (non-empty body).
if let Some(clear_fn_code) = gen_bridge_clear_fn(spec, generator) {
out.push_str("\n\n");
out.push_str(&clear_fn_code);
}
BridgeOutput { imports, code: out }
}