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