modrpc_codegen/codegen/rust/
mod.rs

1use genco::prelude::*;
2
3use mproto_codegen::codegen::{
4    name_util::{camel_to_snake_case, snake_to_upper_camel_case},
5    rust::{rust_type_default_value, rust_type_param_list},
6};
7
8use crate::{
9    Database,
10    ast::{Interface, InterfaceObject},
11};
12
13pub use project::{rust_project_gen, rust_proto_package_gen, rust_role_impl_gen};
14
15mod project;
16
17fn import_qualified(module: Option<impl AsRef<str>>, name: impl AsRef<str>) -> rust::Tokens {
18    if let Some(module) = module {
19        quote! { $(rust::import(format!("{}_modrpc", module.as_ref()), name.as_ref())) }
20    } else {
21        quote! { $(name.as_ref()) }
22    }
23}
24
25pub fn rust_interface(db: &Database, interface: &Interface) -> rust::Tokens {
26    let interface_builder = &rust::import("modrpc", "InterfaceBuilder");
27    let interface_event = &rust::import("modrpc", "InterfaceEvent");
28    let interface_schema = &rust::import("modrpc", "InterfaceSchema");
29
30    let mproto_cx = &mproto_codegen::codegen::CodegenCx::new_with_type_params(
31        db.mproto_db(),
32        Some("crate::proto"),
33        true,
34        &interface.type_params,
35    );
36
37    let mut events_field_tokens = rust::Tokens::new();
38    let mut events_constr_tokens = rust::Tokens::new();
39    for events_list in &interface.events {
40        for event in &events_list.events {
41            let event_type_tokens =
42                mproto_codegen::codegen::rust::rust_type_tokens(mproto_cx, &event.ty);
43            events_field_tokens = quote! {
44                $events_field_tokens
45                pub $(&event.name): $interface_event<$event_type_tokens>,
46            };
47
48            let event_name_tokens = quote! { $("\"")$(&event.name)$("\"") };
49            events_constr_tokens = quote! {
50                $events_constr_tokens
51                $(&event.name): ib.event($event_name_tokens),
52            };
53        }
54    }
55
56    let mut objects_field_tokens = rust::Tokens::new();
57    let mut objects_constr_tokens = rust::Tokens::new();
58    for object in &interface.objects {
59        if db.lookup_interface(&object.construct).is_none() {
60            panic!("failed to lookup interface '{}'", object.construct.name);
61        };
62
63        let object_type_args =
64            &mproto_codegen::codegen::rust::rust_type_arg_list(mproto_cx, &object.type_args, None);
65
66        let object_interface_import = import_qualified(
67            object.construct.module.as_ref(),
68            format!("{}Interface", object.construct.name),
69        );
70        objects_field_tokens = quote! {
71            $objects_field_tokens
72            pub $(&object.name): $(object_interface_import)$(object_type_args),
73        };
74
75        objects_constr_tokens = quote! {
76            $objects_constr_tokens
77            $(&object.name): $(&object.construct.name)Interface::new(ib),
78        };
79    }
80
81    let type_params = &rust_type_param_list(&interface.type_params, None, None);
82
83    let tokens: rust::Tokens = quote! {
84        pub struct $(&interface.name)Interface$(type_params) {
85            $events_field_tokens
86            $objects_field_tokens
87        }
88
89        impl$(type_params) $interface_schema for $(&interface.name)Interface$(type_params) {
90            fn new(ib: &mut $interface_builder) -> Self {
91                Self {
92                    $events_constr_tokens
93                    $objects_constr_tokens
94                }
95            }
96        }
97    };
98
99    tokens
100}
101
102pub fn rust_interface_role(db: &Database, interface: &Interface, role_name: &str) -> rust::Tokens {
103    let role_setup = &rust::import("modrpc", "RoleSetup");
104    let event_tx = &rust::import("modrpc", "EventTx");
105    let event_rx_builder = &rust::import("modrpc", "EventRxBuilder");
106    let interface_role = &rust::import("modrpc", "InterfaceRole");
107    let proto_interface = &rust::import("crate::interface", format!("{}Interface", interface.name));
108    let init_state = &rust::import("crate::proto", format!("{}InitState", interface.name));
109    let role_config = &rust::import(
110        "crate::proto",
111        format!("{}{}Config", interface.name, role_name),
112    );
113
114    let interface_role_name = &format!("{}{}", interface.name, role_name);
115    let interface_role_name_snake = &camel_to_snake_case(interface_role_name);
116
117    let mproto_cx = &mproto_codegen::codegen::CodegenCx::new_with_type_params(
118        db.mproto_db(),
119        Some("crate::proto"),
120        true,
121        &interface.type_params,
122    );
123
124    let mut events_hook_field_tokens = rust::Tokens::new();
125    let mut events_hook_constr_field_tokens = rust::Tokens::new();
126    let mut events_stubs_field_tokens = rust::Tokens::new();
127    let mut events_stubs_constr_field_tokens = rust::Tokens::new();
128    let mut events_clone_tokens = rust::Tokens::new();
129    for events_list in &interface.events {
130        let role_needs_event_tx = events_list
131            .from_roles
132            .iter()
133            .find(|x| x == &role_name)
134            .is_some();
135        let role_needs_event_rx = events_list
136            .to_roles
137            .iter()
138            .find(|x| x == &role_name)
139            .is_some();
140
141        for event in &events_list.events {
142            let payload_ty = mproto_codegen::codegen::rust::rust_type_tokens(&mproto_cx, &event.ty);
143
144            let hook_field_tokens: rust::Tokens = if role_needs_event_tx {
145                quote! {
146                    pub $(&event.name): $event_tx<$(&payload_ty)>,
147                }
148            } else {
149                quote! {}
150            };
151            let hook_constr_tokens: rust::Tokens = if role_needs_event_tx {
152                quote! {
153                    $(&event.name): setup.event_tx(i.$(&event.name)),
154                }
155            } else {
156                quote! {}
157            };
158            let stubs_field_tokens: rust::Tokens = if role_needs_event_rx {
159                quote! {
160                    pub $(&event.name): $event_rx_builder<$(&payload_ty)>,
161                }
162            } else {
163                quote! {}
164            };
165            let stubs_constr_tokens: rust::Tokens = if role_needs_event_rx {
166                quote! {
167                    $(&event.name): setup.event_rx(i.$(&event.name)),
168                }
169            } else {
170                quote! {}
171            };
172            let clone_tokens: rust::Tokens = if role_needs_event_tx {
173                quote! {
174                    $(&event.name): self.$(&event.name).clone(),
175                }
176            } else {
177                quote! {}
178            };
179
180            events_hook_field_tokens = quote! {
181                $events_hook_field_tokens
182                $hook_field_tokens
183            };
184            events_hook_constr_field_tokens = quote! {
185                $events_hook_constr_field_tokens
186                $hook_constr_tokens
187            };
188            events_stubs_field_tokens = quote! {
189                $events_stubs_field_tokens
190                $stubs_field_tokens
191            };
192            events_stubs_constr_field_tokens = quote! {
193                $events_stubs_constr_field_tokens
194                $stubs_constr_tokens
195            };
196            events_clone_tokens = quote! {
197                $events_clone_tokens
198                $clone_tokens
199            };
200        }
201    }
202
203    let mut objects_hook_field_tokens = rust::Tokens::new();
204    let mut objects_hook_constr_tokens = rust::Tokens::new();
205    let mut objects_hook_constr_stubs_tokens = rust::Tokens::new();
206    let mut objects_hook_constr_field_tokens = rust::Tokens::new();
207    let mut objects_stubs_field_tokens = rust::Tokens::new();
208    let mut objects_clone_tokens = rust::Tokens::new();
209    let mut i = 0;
210    for object in &interface.objects {
211        let Some(object_interface) = db.lookup_interface(&object.construct) else {
212            panic!("failed to lookup interface '{}'", object.construct.name);
213        };
214
215        let object_role_names = object.get_roles_for_parent_role(object_interface, role_name);
216        if object_role_names.is_empty() {
217            panic!(
218                "object '{}' failed to find roles '{}'",
219                object.name, role_name
220            );
221        };
222
223        for object_role_name in &object_role_names {
224            let construct_module = object.construct.module.as_ref();
225            let object_interface_role_name =
226                &format!("{}{}", object.construct.name, object_role_name);
227
228            let object_field_name = if object_role_names.len() > 1 {
229                &format!("{}_{}", object.name, camel_to_snake_case(object_role_name))
230            } else {
231                &object.name
232            };
233
234            let object_type_args = &mproto_codegen::codegen::rust::rust_type_arg_list(
235                mproto_cx,
236                &object.type_args,
237                None,
238            );
239
240            let hook_field_tokens = quote! {
241                pub $(object_field_name): $(import_qualified(construct_module, object_interface_role_name))$(object_type_args),
242            };
243
244            let object_config: &rust::Tokens = &if object_interface
245                .has_config_for_role(object_role_name)
246            {
247                quote! { config.$(object_field_name) }
248            } else {
249                quote! { $(import_qualified(construct_module, format!("{}Config", object_interface_role_name))) { } }
250            };
251
252            let object_init: &rust::Tokens = &if object_interface.has_state(db) {
253                quote! { init.$(object_field_name) }
254            } else {
255                quote! { $(import_qualified(construct_module, format!("{}InitState", object.construct.name))) { } }
256            };
257
258            let mut hook_constr_tokens = quote! {
259                let ($(object_field_name)_stubs, $(object_field_name)_hooks) =
260                    $(import_qualified(construct_module, format!("{}Role", object_interface_role_name)))::setup_worker(
261                        &i.$(&object.name), setup, &$(object_config), &$(object_init),
262                    );
263                let $(object_field_name)_builder = $(import_qualified(construct_module, format!("{}Builder", object_interface_role_name)))::new(
264                    $("\"")$(interface_role_name_snake).$(&object.name)$("\""),
265                    $(object_field_name)_hooks,
266                    $(object_field_name)_stubs,
267                    &$(object_config),
268                    $(object_init).clone(),
269                );
270                let $(object_field_name) = $(object_field_name)_builder.create_handle(setup);
271            };
272            let hook_constr_field_tokens = quote! {
273                $(object_field_name),
274            };
275
276            let clone_tokens = quote! {
277                $(object_field_name): self.$(object_field_name).clone(),
278            };
279
280            // For impl setup, need to determine if the user needs to provide any `impl`s for this
281            // role. If the user doesn't need to provide any `impl`s, we auto-implement the stubs for
282            // this object.
283
284            let stubs_field_tokens: rust::Tokens;
285            let hook_constr_stubs_tokens: rust::Tokens;
286            if object_interface.requires_impls_for_role(object_role_name) {
287                // User needs to provide impls
288
289                stubs_field_tokens = quote! {
290                    pub $(object_field_name): $(import_qualified(construct_module, format!("{}Builder", object_interface_role_name)))$(object_type_args),
291                };
292
293                hook_constr_stubs_tokens = quote! {
294                    $(object_field_name): $(object_field_name)_builder,
295                };
296            } else {
297                // User does not need to provide impls
298
299                hook_constr_tokens = quote! {
300                    $hook_constr_tokens
301                    $(object_field_name)_builder.build(setup);
302                };
303
304                stubs_field_tokens = quote! {};
305
306                hook_constr_stubs_tokens = quote! {};
307            }
308
309            hook_constr_tokens = quote! {
310                setup.push_object_path($("\"")$(&object.name)$("\""));
311                $hook_constr_tokens
312                setup.pop_object_path();
313            };
314
315            if i > 0 {
316                objects_hook_field_tokens = quote! {
317                    $objects_hook_field_tokens
318                    $hook_field_tokens
319                };
320                objects_hook_constr_tokens = quote! {
321                    $objects_hook_constr_tokens
322                    $hook_constr_tokens
323                };
324                objects_hook_constr_stubs_tokens = quote! {
325                    $objects_hook_constr_stubs_tokens
326                    $hook_constr_stubs_tokens
327                };
328                objects_hook_constr_field_tokens = quote! {
329                    $objects_hook_constr_field_tokens
330                    $hook_constr_field_tokens
331                };
332                objects_stubs_field_tokens = quote! {
333                    $objects_stubs_field_tokens
334                    $stubs_field_tokens
335                };
336                objects_clone_tokens = quote! {
337                    $objects_clone_tokens
338                    $clone_tokens
339                };
340            } else {
341                objects_hook_field_tokens = hook_field_tokens;
342                objects_stubs_field_tokens = stubs_field_tokens;
343                objects_hook_constr_tokens = hook_constr_tokens;
344                objects_hook_constr_stubs_tokens = hook_constr_stubs_tokens;
345                objects_hook_constr_field_tokens = hook_constr_field_tokens;
346                objects_clone_tokens = clone_tokens;
347            }
348
349            i += 1;
350        }
351    }
352
353    ////////////////////////////////////
354
355    let type_params = &rust_type_param_list(&interface.type_params, None, None);
356    let type_params_no_lifetime = &rust_type_param_list(&interface.type_params, None, None);
357    let type_params_no_lifetime_bounded =
358        &rust_type_param_list(&interface.type_params, None, Some(quote! { mproto::Owned }));
359
360    let mut interface_type_params_tokens = rust::Tokens::new();
361    if interface.type_params.len() > 0 {
362        interface_type_params_tokens = quote! { $(&interface.type_params[0]) };
363        for type_param in &interface.type_params[1..] {
364            interface_type_params_tokens = quote! { $interface_type_params_tokens, $(type_param) };
365        }
366    }
367    let interface_type_params_tokens = &interface_type_params_tokens;
368
369    ////////////////////////////////////
370
371    let phantom_data: &rust::Tokens = if interface.type_params.len() > 1 {
372        &quote! { _phantom: std::marker::PhantomData<($interface_type_params_tokens)>, }
373    } else if interface.type_params.len() == 1 {
374        &quote! { _phantom: std::marker::PhantomData<$interface_type_params_tokens>, }
375    } else {
376        &quote! {}
377    };
378
379    let role_config_def = db
380        .mproto_db()
381        .lookup_type_def(&mproto_codegen::ast::QualifiedIdentifier::local(format!(
382            "{}{}Config",
383            interface.name, role_name
384        )))
385        .expect("role config struct def");
386
387    let init_state_with_args: rust::Tokens = if interface.has_state(db) {
388        quote! { $(init_state)$(type_params_no_lifetime) }
389    } else {
390        quote! { $(init_state) }
391    };
392
393    quote! {
394        pub struct $(interface_role_name)Hooks$(type_params) {
395            $events_hook_field_tokens
396            $objects_hook_field_tokens
397            $phantom_data
398        }
399
400        pub struct $(interface_role_name)Stubs$(type_params) {
401            $events_stubs_field_tokens
402            $objects_stubs_field_tokens
403            $phantom_data
404        }
405
406        pub struct $(interface_role_name)Role$(type_params_no_lifetime) {
407            $phantom_data
408        }
409
410        impl$(type_params_no_lifetime_bounded) $interface_role for $(&interface.name)$(role_name)Role$(type_params_no_lifetime) {
411            type Interface = $(proto_interface)$(type_params_no_lifetime);
412            type Config = $(role_config)$(rust_type_param_list(&role_config_def.params, None, None));
413            type Init = $init_state_with_args;
414            type Stubs = $(interface_role_name)Stubs$(type_params);
415            type Hooks = $(interface_role_name)Hooks$(type_params);
416
417            fn setup_worker(
418                i: &Self::Interface,
419                setup: &mut $role_setup,
420                config: &Self::Config,
421                init: &Self::Init,
422            ) -> (Self::Stubs, Self::Hooks) {
423                $objects_hook_constr_tokens
424
425                (
426                    Self::Stubs {
427                        $events_stubs_constr_field_tokens
428                        $objects_hook_constr_stubs_tokens
429                        $(if !interface.type_params.is_empty() { _phantom: std::marker::PhantomData, })
430                    },
431                    Self::Hooks {
432                        $events_hook_constr_field_tokens
433                        $objects_hook_constr_field_tokens
434                        $(if !interface.type_params.is_empty() { _phantom: std::marker::PhantomData, })
435                    },
436                )
437            }
438        }
439
440        impl$(type_params) Clone for $(interface_role_name)Hooks$(type_params) {
441            fn clone(&self) -> Self {
442                Self {
443                    $events_clone_tokens
444                    $objects_clone_tokens
445                    $(if !interface.type_params.is_empty() { _phantom: std::marker::PhantomData, })
446                }
447            }
448        }
449    }
450}
451
452pub fn rust_interface_role_impl(
453    db: &Database,
454    interface: &Interface,
455    role_name: &str,
456) -> rust::Tokens {
457    if !interface.has_private_event_impls_for_role(role_name)
458        && !interface.has_methods_for_role(role_name)
459        && !interface.has_config_for_role(role_name)
460        && !interface.has_impls_for_role(role_name)
461    {
462        return quote! {};
463    }
464
465    let role_config = &rust::import(
466        "crate::proto",
467        format!("{}{}Config", interface.name, role_name),
468    );
469    let init_state = &rust::import("crate::proto", format!("{}InitState", interface.name));
470    let role_setup = &rust::import("modrpc", "RoleSetup");
471
472    let interface_role_name = &format!("{}{}", interface.name, role_name);
473
474    let mproto_cx = &mproto_codegen::codegen::CodegenCx::new_with_type_params(
475        db.mproto_db(),
476        Some("crate::proto"),
477        true,
478        &interface.type_params,
479    );
480
481    let type_params = &rust_type_param_list(&interface.type_params, None, None);
482    let type_params_bounded =
483        &rust_type_param_list(&interface.type_params, None, Some(quote! { mproto::Owned }));
484    let type_params_no_lifetime = &rust_type_param_list(&interface.type_params, None, None);
485
486    let mut event_handler_stubs = rust::Tokens::new();
487    for events_list in &interface.events {
488        if !events_list
489            .to_roles
490            .iter()
491            .find(|x| x.as_str() == role_name)
492            .is_some()
493        {
494            continue;
495        }
496
497        for event in &events_list.events {
498            if !event.is_private {
499                continue;
500            }
501
502            let payload_ty = mproto_codegen::codegen::rust::rust_type_tokens(mproto_cx, &event.ty);
503
504            event_handler_stubs = quote! {
505                $event_handler_stubs
506                let $(&event.name) = self.stubs.$(&event.name)
507                    .queued(setup, async move |_source, _event: $(payload_ty)| {
508                    })
509                    .load_balance();
510            };
511        }
512    }
513
514    let mut methods = rust::Tokens::new();
515    for methods_list in &interface.methods {
516        if !methods_list
517            .roles
518            .iter()
519            .find(|x| x.as_str() == role_name)
520            .is_some()
521        {
522            continue;
523        }
524
525        for method in &methods_list.methods {
526            let input_ty =
527                &mproto_codegen::codegen::rust::rust_type_tokens(mproto_cx, &method.input_ty);
528            let output_ty =
529                &mproto_codegen::codegen::rust::rust_type_tokens(mproto_cx, &method.output_ty);
530
531            methods = quote! {
532                $methods
533                pub $(
534                    if method.is_async { async } else { }
535                ) fn $(&method.name)(
536                    &self,
537                    input: impl mproto::Encode + for<'a> mproto::Decode<'a> + mproto::Compatible<$input_ty>,
538                ) -> $output_ty {
539                    $(rust_type_default_value(
540                        mproto_cx,
541                        &method.output_ty,
542                    ))
543                }
544            };
545        }
546    }
547
548    if !methods.is_empty() {
549        methods = quote! {
550            impl$(type_params_bounded) $(interface_role_name)$(type_params) {
551                $methods
552            }
553        };
554    }
555
556    let role_config_def = db
557        .mproto_db()
558        .lookup_type_def(&mproto_codegen::ast::QualifiedIdentifier::local(format!(
559            "{}{}Config",
560            interface.name, role_name
561        )))
562        .expect("role config struct def");
563
564    let init_state_with_args: &rust::Tokens = &if interface.has_state(db) {
565        quote! { $(init_state)$(type_params_no_lifetime) }
566    } else {
567        quote! { $(init_state) }
568    };
569
570    quote! {
571        #[derive(Clone)]
572        pub struct $(interface_role_name)$(type_params) {
573            hooks: crate::$(interface_role_name)Hooks$(type_params),
574        }
575
576        pub struct $(interface_role_name)Builder$(type_params) {
577            pub name: &'static str,
578            pub hooks: crate::$(interface_role_name)Hooks$(type_params),
579            pub stubs: crate::$(interface_role_name)Stubs$(type_params),
580            pub init: $init_state_with_args,
581        }
582
583        impl$(type_params_bounded) $(interface_role_name)Builder$(type_params) {
584            pub fn new(
585                name: &'static str,
586                hooks: crate::$(interface_role_name)Hooks$(type_params),
587                stubs: crate::$(interface_role_name)Stubs$(type_params),
588                config: &$(role_config)$(rust_type_param_list(&role_config_def.params, None, None)),
589                init: $init_state_with_args,
590            ) -> Self {
591                Self { name, hooks, stubs, init }
592            }
593
594            pub fn create_handle(
595                &self,
596                setup: &$role_setup,
597            ) -> crate::$(interface_role_name)$(type_params) {
598                crate::$(interface_role_name) {
599                    hooks: self.hooks.clone(),
600                }
601            }
602
603            pub fn build(
604                self,
605                setup: &$role_setup,
606            ) {
607                $event_handler_stubs
608            }
609        }
610
611        $methods
612    }
613}
614
615pub fn request_impl_stub(
616    mproto_cx: &mproto_codegen::codegen::CodegenCx,
617    object: &InterfaceObject,
618) -> rust::Tokens {
619    let object_name_upper_camel = &snake_to_upper_camel_case(&object.name);
620
621    let request_ty =
622        mproto_codegen::codegen::rust::rust_type_lazy_tokens(mproto_cx, &object.type_args[0]);
623    let response_ty =
624        mproto_codegen::codegen::rust::rust_type_tokens(mproto_cx, &object.type_args[1]);
625
626    quote! {
627        pub struct $(object_name_upper_camel)Handler {
628        }
629
630        impl std_modrpc::RequestHandlerReply for $(object_name_upper_camel)Handler {
631            type Input<'a> = $(request_ty);
632            type Output = $(response_ty);
633
634            async fn call<'a>(
635                &'a mut self,
636                mut cx: std_modrpc::RequestContext<'a, Self::Output>,
637                request: Self::Input<'a>,
638            ) -> Option<()> {
639                None
640            }
641        }
642    }
643}
644
645pub struct RustInterfaceImpl {
646    pub main_rs: rust::Tokens,
647    pub handlers: Vec<(String, rust::Tokens)>,
648}
649
650impl RustInterfaceImpl {
651    pub fn generate(
652        mproto_db: &mproto_codegen::Database,
653        package_name: &str,
654        interface: &Interface,
655        role_name: &str,
656    ) -> Self {
657        let interface_name = &interface.name;
658        let interface_role_name = &format!("{}{}", interface.name, role_name);
659        let package_name = &package_name.replace("-", "_");
660
661        let def_crate = format!("{}_modrpc", package_name);
662        let def_crate = def_crate.as_str();
663        let def_source = Some(def_crate);
664
665        let mproto_cx = &mproto_codegen::codegen::CodegenCx::new_with_type_params(
666            mproto_db,
667            def_source,
668            true,
669            &interface.type_params,
670        );
671
672        let rc = &rust::import("std::rc", "Rc");
673        let ref_cell = &rust::import("std::cell", "RefCell");
674        let block_on = &rust::import("futures_lite::future", "block_on");
675        let modmesh_session = &rust::import("modmesh_endpoint", "ModmeshSession");
676
677        let mut register_handlers = rust::Tokens::new();
678        let mut handlers = Vec::new();
679        for object in &interface.objects {
680            if object.construct.name == "Request"
681                && object.construct.module.as_ref().map(|s| s.as_ref()) == Some("std")
682            {
683                // TODO also ensure that this interface role acts as the request server role.
684
685                let object_name_upper_camel = &snake_to_upper_camel_case(&object.name);
686                register_handlers = quote! {
687                    $register_handlers
688                    cx.stubs.$(&object.name).build_replier(s, $(object_name_upper_camel)Handler {});
689                };
690
691                handlers.push((object.name.clone(), request_impl_stub(mproto_cx, object)));
692            }
693        }
694
695        let main_rs = quote! {
696            struct $(interface_role_name)State {
697            }
698
699            fn main() {
700                let state = Rc::new(RefCell::new($(interface_role_name)State {
701                }));
702
703                loop {
704                    $block_on(async move {
705                        if let Ok(mut modmesh) = $modmesh_session::connect(("127.0.0.1", 13016)).await {
706                            modmesh.host_service::<$def_crate::$interface_role_name>(
707                                "untitled-service".into(),
708                                $(def_crate)::$(interface_name)InitState { },
709                                |cx| start_$(package_name)(cx, state.clone())
710                            ).await;
711
712                            modmesh.run().await;
713                        }
714
715                        // TODO
716                        std::thread::sleep(std::time::Duration::from_secs(5));
717                        println!("Retrying modmesh connection...");
718                    });
719                }
720            }
721
722            fn start_$(package_name)(
723                cx: modrpc::RoleWorkerContext<$def_crate::$(interface_role_name)Role>,
724                state: $rc<$ref_cell<$(interface_role_name)State>>,
725            ) {
726                $register_handlers
727            }
728        };
729
730        Self { main_rs, handlers }
731    }
732}
733
734pub fn rust_interface_init_state_tokens(db: &mut Database, interface: &Interface) -> rust::Tokens {
735    let init_state_struct = crate::codegen::interface_init_state(db, interface);
736    let init_state_struct_id = db
737        .mproto_db_mut()
738        .local_mut()
739        .new_type_def(init_state_struct);
740
741    let mproto_cx = &mproto_codegen::codegen::CodegenCx::new_with_type_params(
742        db.mproto_db(),
743        Some("crate::proto"),
744        true,
745        &interface.type_params,
746    );
747
748    quote! {
749        $(mproto_codegen::codegen::rust::rust_type_def(
750            &mproto_cx,
751            db.mproto_db().local().type_def(init_state_struct_id)
752        ))
753    }
754}
755
756pub fn rust_interface_role_config_tokens(
757    db: &mut Database,
758    interface: &Interface,
759    role_name: &str,
760) -> rust::Tokens {
761    let config_struct = crate::codegen::interface_role_config(
762        db,
763        &mproto_codegen::codegen::CodegenCx::new_with_type_params(
764            db.mproto_db(),
765            Some("crate::proto"),
766            true,
767            &interface.type_params,
768        ),
769        interface,
770        role_name,
771    );
772    let config_struct_id = db.mproto_db_mut().local_mut().new_type_def(config_struct);
773
774    quote! {
775        $(mproto_codegen::codegen::rust::rust_type_def(
776            &mproto_codegen::codegen::CodegenCx::new_with_type_params(
777                db.mproto_db(), Some("crate::proto"), true, &interface.type_params,
778            ),
779            db.mproto_db().local().type_def(config_struct_id)
780        ))
781    }
782}