1#![warn(
46 missing_docs,
47 missing_copy_implementations,
48 missing_debug_implementations
49)]
50
51use std::{
52 env,
53 fs::{DirBuilder, File},
54 io::Write,
55 path::Path,
56};
57
58use thiserror::Error;
59
60use crate::{
61 json::generate_json,
62 parser::{ApiParser, Field, FieldSize, Message, Type, Union, VL_API_PREFIX, VL_API_SUFFIX},
63};
64
65mod json;
66mod parser;
67
68#[derive(Debug, Error)]
70#[non_exhaustive]
71pub enum Error {
72 #[error("Parser error")]
74 Parser(#[from] parser::Error),
75 #[error("I/O error")]
77 Io(#[from] std::io::Error),
78 #[error("Failed to generate JSON")]
80 Json(#[from] serde_json::Error),
81 #[error("{0}")]
83 Unimplemented(String),
84}
85
86fn to_upper_camel_case(s: &str) -> String {
87 s.split('_')
88 .flat_map(|word| {
89 let word = word.to_ascii_lowercase();
90 let mut chars = word.chars();
91 let capital = chars.next().map(|x| x.to_ascii_uppercase());
92 capital.into_iter().chain(chars).collect::<Vec<_>>()
93 })
94 .collect()
95}
96
97fn to_rust_type(r#type: &str) -> Result<String, Error> {
98 Ok(if let Some(t) = r#type.strip_prefix(VL_API_PREFIX) {
99 if let Some(t) = t.strip_suffix(VL_API_SUFFIX) {
100 to_upper_camel_case(t)
101 } else {
102 r#type.to_string()
103 }
104 } else if r#type == "string" {
105 return Err(Error::Unimplemented(
106 "string type not implemented".to_string(),
107 ));
108 } else {
109 r#type.to_string()
110 })
111}
112
113#[derive(Debug)]
137pub struct Builder {
138 parser: ApiParser,
139
140 module: String,
141 output_file: File,
142 output_json_file: File,
143}
144
145impl Builder {
146 pub fn new(input_file: &str, output_dir: &str) -> Result<Self, Error> {
151 let in_build_script = env::var("OUT_DIR").is_ok() && env::var("CARGO_MANIFEST_DIR").is_ok();
152 if in_build_script {
153 println!("cargo:cargo-rerun-if-changed={}", input_file);
154 }
155
156 let input_file_name = Path::new(input_file).iter().next_back().unwrap();
158 let module = Path::new(input_file_name)
159 .file_stem()
160 .unwrap()
161 .to_string_lossy()
162 .to_string();
163
164 DirBuilder::new().recursive(true).create(output_dir)?;
165 let output_file = Path::new(output_dir).join(format!("{}_api.rs", module));
166 let output_json_file = Path::new(output_dir).join(format!("{}.api.json", module));
167
168 let parser = ApiParser::new(input_file)?;
169
170 if in_build_script {
171 for import in parser.imports() {
172 println!("cargo:cargo-rerun-if-changed={}", import);
173 }
174 }
175
176 Ok(Self {
177 parser,
178 module,
179 output_file: File::create(&output_file)?,
180 output_json_file: File::create(&output_json_file)?,
181 })
182 }
183
184 pub fn generate(self) -> Result<(), Error> {
189 ApiGenContext {
190 parser: &self.parser,
191 module: self.module,
192 output_file: self.output_file,
193 output_json_file: self.output_json_file,
194 }
195 .generate()
196 }
197}
198
199struct ApiGenContext<'a> {
204 parser: &'a ApiParser,
205
206 module: String,
207 output_file: File,
208 output_json_file: File,
209}
210
211impl ApiGenContext<'_> {
212 fn generate_message(&mut self, id: usize, message: &Message) -> Result<(), Error> {
213 let upper_camel_name = to_upper_camel_case(message.name());
214
215 if let Some(comment) = message.comment() {
216 writeln!(
217 self.output_file,
218 "#[doc = \"{}\"]",
219 comment.replace("\"", "\\\"")
220 )?;
221 }
222 let opt_derives = if message.manual_print() {
223 ""
224 } else {
225 "Debug, PartialEq, "
226 };
227 writeln!(self.output_file, "#[derive({}Copy, Clone)]", opt_derives)?;
228 writeln!(self.output_file, "#[repr(C, packed)]")?;
229 writeln!(self.output_file, "pub struct {} {{", upper_camel_name)?;
230 for field in message.fields() {
231 writeln!(
233 self.output_file,
234 " pub {}: {},",
235 field.name,
236 to_rust_type(&field.r#type)?
237 )?;
238 }
239 writeln!(self.output_file, "}}")?;
240 writeln!(self.output_file)?;
241
242 writeln!(self.output_file, "impl {} {{", upper_camel_name)?;
243 writeln!(self.output_file, " pub const MSG_ID: u16 = {};", id)?;
244 writeln!(self.output_file)?;
245 writeln!(self.output_file, " pub fn msg_id() -> u16 {{")?;
246 writeln!(self.output_file, " msg_id_base() + Self::MSG_ID")?;
247 writeln!(self.output_file, " }}")?;
248 writeln!(self.output_file, "}}")?;
249 writeln!(self.output_file)?;
250
251 writeln!(self.output_file, "impl Default for {} {{", upper_camel_name)?;
252 writeln!(self.output_file, " fn default() -> Self {{")?;
253 writeln!(self.output_file, " Self {{")?;
254 for field in message.fields() {
255 if field.name == "_vl_msg_id" {
256 writeln!(self.output_file, " _vl_msg_id: Self::msg_id(),")?;
257 } else {
258 writeln!(
259 self.output_file,
260 " {}: Default::default(),",
261 field.name,
262 )?;
263 }
264 }
265 writeln!(self.output_file, " }}")?;
266 writeln!(self.output_file, " }}")?;
267 writeln!(self.output_file, "}}")?;
268 writeln!(self.output_file)?;
269
270 self.generate_endian_swap(message.name(), message.fields())?;
271
272 writeln!(
273 self.output_file,
274 "unsafe extern \"C\" fn {}_endian(a: *mut {}, to_net: bool) {{",
275 message.name(),
276 upper_camel_name
277 )?;
278 writeln!(
279 self.output_file,
280 " ::vpp_plugin::vlibapi::EndianSwap::endian_swap(&mut *a, to_net);"
281 )?;
282 writeln!(self.output_file, "}}")?;
283 writeln!(self.output_file)?;
284
285 writeln!(
286 self.output_file,
287 "unsafe extern \"C\" fn {}_format(s: *mut u8, args: *mut ::vpp_plugin::bindings::va_list) -> *mut u8 {{",
288 message.name()
289 )?;
290 writeln!(
291 self.output_file,
292 " let mut args = ::std::mem::transmute::<*mut ::vpp_plugin::bindings::va_list, ::vpp_plugin::macro_support::va_list::VaList<'_>>(args);"
293 )?;
294 writeln!(
295 self.output_file,
296 " let t = args.get::<*const {}>();",
297 upper_camel_name
298 )?;
299 writeln!(
300 self.output_file,
301 " let mut s = ::vpp_plugin::vppinfra::vec::Vec::from_raw(s);"
302 )?;
303 writeln!(
304 self.output_file,
305 " s.extend(format!(\"{{:?}}\", &*t).as_bytes());"
306 )?;
307 writeln!(self.output_file, " s.into_raw()")?;
308 writeln!(self.output_file, "}}")?;
309 writeln!(self.output_file)?;
310 writeln!(
311 self.output_file,
312 "unsafe extern \"C\" fn {}_calc_size(_a: *mut {}) -> ::vpp_plugin::bindings::uword {{",
313 message.name(),
314 upper_camel_name
315 )?;
316 writeln!(
318 self.output_file,
319 " std::mem::size_of::<{}>() as ::vpp_plugin::bindings::uword",
320 upper_camel_name
321 )?;
322 writeln!(self.output_file, "}}")?;
323 writeln!(self.output_file)?;
324 Ok(())
325 }
326
327 fn generate_messages(&mut self) -> Result<(), Error> {
328 for (id, message) in self.parser.messages().iter().enumerate() {
329 self.generate_message(id, message)?;
330 }
331 Ok(())
332 }
333
334 fn generate_alias(&mut self, alias: &Field) -> Result<(), Error> {
335 let upper_camel_name = to_upper_camel_case(&alias.name);
336 if let Some(FieldSize::Fixed(length)) = alias.size {
338 writeln!(
339 self.output_file,
340 "pub type {} = [{}; {}];",
341 upper_camel_name,
342 to_rust_type(&alias.r#type)?,
343 length
344 )?;
345 } else {
346 writeln!(
347 self.output_file,
348 "pub type {} = {};",
349 upper_camel_name,
350 to_rust_type(&alias.r#type)?
351 )?;
352 }
353
354 Ok(())
355 }
356
357 fn generate_aliases(&mut self) -> Result<(), Error> {
358 for message in self.parser.aliases() {
359 self.generate_alias(message)?;
360 }
361 Ok(())
362 }
363
364 fn generate_enums(&mut self) -> Result<(), Error> {
365 if let Some(e) = self.parser.enums().first() {
366 return Err(Error::Unimplemented(format!(
367 "Generating code for enums is not yet implemented (enum type {})",
368 e.name()
369 )));
370 }
371 if let Some(e) = self.parser.enumflags().first() {
372 return Err(Error::Unimplemented(format!(
373 "Generating code for enumflags is not yet implemented (enumflag type {})",
374 e.name()
375 )));
376 }
377 Ok(())
378 }
379
380 fn generate_union(&mut self, un: &Union) -> Result<(), Error> {
381 let upper_camel_name = to_upper_camel_case(un.name());
382
383 if let Some(comment) = un.comment() {
384 writeln!(
385 self.output_file,
386 "#[doc = \"{}\"]",
387 comment.replace("\"", "\\\"")
388 )?;
389 }
390 writeln!(self.output_file, "#[derive(Copy, Clone)]",)?;
391 writeln!(self.output_file, "#[repr(C, packed)]")?;
392 writeln!(self.output_file, "pub union {} {{", upper_camel_name)?;
393 for field in un.fields() {
394 writeln!(
396 self.output_file,
397 " pub {}: {},",
398 field.name,
399 to_rust_type(&field.r#type)?
400 )?;
401 }
402 writeln!(self.output_file, "}}")?;
403 writeln!(self.output_file)?;
404 writeln!(
405 self.output_file,
406 "unsafe extern \"C\" fn {}_endian(a: *mut {}, _to_net: bool) {{",
407 un.name(),
408 upper_camel_name
409 )?;
410 for field in un.fields() {
411 match field.r#type.as_str() {
413 "u8" | "string" | "bool" => {
414 writeln!(
415 self.output_file,
416 " // (*a).{} = (*a).{} (no-op)",
417 field.name, field.name
418 )?;
419 }
420 "u16" | "u32" | "u64" | "i16" | "i32" | "i64" => {
421 writeln!(
422 self.output_file,
423 " (*a).{} = (*a).{}.to_be();",
424 field.name, field.name
425 )?;
426 }
427 "f64" => {
428 writeln!(
429 self.output_file,
430 " (*a).{} = f64::from_be_bytes((*a).{}.to_be_bytes());",
431 field.name, field.name
432 )?;
433 }
434 _ => {
435 writeln!(
436 self.output_file,
437 " {}_endian(::std::ptr::addr_of_mut!((*a).{}), to_net);",
438 field.r#type, field.name
439 )?;
440 }
441 }
442 }
443 writeln!(self.output_file, "}}")?;
444 writeln!(self.output_file)?;
445 writeln!(
446 self.output_file,
447 "unsafe extern \"C\" fn {}_calc_size(_a: *mut {}) -> ::vpp_plugin::bindings::uword {{",
448 un.name(),
449 upper_camel_name
450 )?;
451 writeln!(
453 self.output_file,
454 " std::mem::size_of::<{}>() as ::vpp_plugin::bindings::uword",
455 upper_camel_name
456 )?;
457 writeln!(self.output_file, "}}")?;
458 writeln!(self.output_file)?;
459 Ok(())
460 }
461
462 fn generate_unions(&mut self) -> Result<(), Error> {
463 for un in self.parser.unions() {
464 self.generate_union(un)?;
465 }
466 Ok(())
467 }
468
469 fn generate_endian_swap(&mut self, name: &str, fields: &[Field]) -> Result<(), Error> {
470 writeln!(
471 self.output_file,
472 "impl ::vpp_plugin::vlibapi::EndianSwap for {} {{",
473 to_upper_camel_case(name)
474 )?;
475 writeln!(
476 self.output_file,
477 " fn endian_swap(&mut self, to_net: bool) {{",
478 )?;
479 writeln!(self.output_file, " let _ = to_net;",)?;
481 for field in fields {
482 match field.r#type.as_str() {
484 "u8" | "string" | "bool" => {
485 writeln!(
486 self.output_file,
487 " // self.{} = self.{} (no-op)",
488 field.name, field.name
489 )?;
490 }
491 "u16" | "u32" | "u64" | "i16" | "i32" | "i64" => {
492 writeln!(
493 self.output_file,
494 " self.{} = self.{}.to_be();",
495 field.name, field.name
496 )?;
497 }
498 "f64" => {
499 writeln!(
500 self.output_file,
501 " self.{} = f64::from_be_bytes(self.{}.to_be_bytes());",
502 field.name, field.name
503 )?;
504 }
505 _ => {
506 writeln!(
507 self.output_file,
508 " ::vpp_plugin::vlibapi::EndianSwap::endian_swap(&mut self.{}, to_net);",
509 field.name
510 )?;
511 }
512 }
513 }
514 writeln!(self.output_file, " }}",)?;
515 writeln!(self.output_file, "}}")?;
516 writeln!(self.output_file)?;
517
518 Ok(())
519 }
520
521 fn generate_type(&mut self, t: &Type) -> Result<(), Error> {
522 let upper_camel_name = to_upper_camel_case(t.name());
523
524 let opt_derives = if t.manual_print() {
525 ""
526 } else {
527 "Debug, PartialEq, Default, "
528 };
529 writeln!(self.output_file, "#[derive({}Copy, Clone)]", opt_derives)?;
530 writeln!(self.output_file, "#[repr(C, packed)]")?;
531 writeln!(self.output_file, "pub struct {} {{", upper_camel_name)?;
532 for field in t.fields() {
533 writeln!(
535 self.output_file,
536 " pub {}: {},",
537 field.name,
538 to_rust_type(&field.r#type)?
539 )?;
540 }
541 writeln!(self.output_file, "}}")?;
542 writeln!(self.output_file)?;
543 if !t.manual_endian() {
544 self.generate_endian_swap(t.name(), t.fields())?;
545 }
546 writeln!(
547 self.output_file,
548 "unsafe extern \"C\" fn vl_api_{}_t_calc_size(_a: *mut {}) -> ::vpp_plugin::bindings::uword {{",
549 t.name(),
550 upper_camel_name
551 )?;
552 writeln!(
554 self.output_file,
555 " std::mem::size_of::<{}>() as ::vpp_plugin::bindings::uword",
556 upper_camel_name
557 )?;
558 writeln!(self.output_file, "}}")?;
559 writeln!(self.output_file)?;
560 Ok(())
561 }
562
563 fn generate_types(&mut self) -> Result<(), Error> {
564 for t in self.parser.types() {
565 self.generate_type(t)?;
566 }
567 Ok(())
568 }
569
570 fn generate_register(&mut self) -> Result<(), Error> {
571 writeln!(self.output_file, "pub trait Handlers {{")?;
572 for service in self.parser.services() {
573 let caller_upper_camel = to_upper_camel_case(service.caller());
574 if service.reply() == "null" {
575 writeln!(
576 self.output_file,
577 " fn {}(vm: &::vpp_plugin::vlib::BarrierHeldMainRef, mp: &{});",
578 service.caller(),
579 caller_upper_camel
580 )?;
581 } else {
582 let reply_message = format!(
584 "::vpp_plugin::vlibapi::Message<{}>",
585 to_upper_camel_case(service.reply())
586 );
587 let retval_in_reply_msg = self
588 .parser
589 .message(service.reply())
590 .map(|reply| reply.has_retval())
591 .unwrap_or_default();
592 if retval_in_reply_msg {
593 writeln!(
594 self.output_file,
595 " fn {}(vm: &::vpp_plugin::vlib::BarrierHeldMainRef, mp: &{}) -> Result<{}, i32>;",
596 service.caller(),
597 caller_upper_camel,
598 reply_message
599 )?;
600 } else {
601 writeln!(
602 self.output_file,
603 " fn {}(vm: &::vpp_plugin::vlib::BarrierHeldMainRef, mp: &{}) -> {};",
604 service.caller(),
605 caller_upper_camel,
606 reply_message
607 )?;
608 }
609 }
610 }
611 writeln!(self.output_file, "}}")?;
612 writeln!(self.output_file)?;
613
614 for service in self.parser.services() {
615 let caller_upper_camel = to_upper_camel_case(service.caller());
616 writeln!(
617 self.output_file,
618 "unsafe extern \"C\" fn {}_handler_raw<H: Handlers>(mp: *mut {}) {{",
619 service.caller(),
620 caller_upper_camel
621 )?;
622 writeln!(
623 self.output_file,
624 " let vm = ::vpp_plugin::vlib::BarrierHeldMainRef::from_ptr_mut("
625 )?;
626 writeln!(
627 self.output_file,
628 " ::vpp_plugin::bindings::vlib_get_main_not_inline(),"
629 )?;
630 writeln!(self.output_file, " );")?;
631 writeln!(self.output_file, " let mp = &*mp;")?;
632 if service.reply() == "null" {
633 writeln!(self.output_file, " H::{}(vm, mp);", service.caller())?;
634 } else {
635 let retval_in_reply_msg = self
636 .parser
637 .message(service.reply())
638 .map(|reply| reply.has_retval())
639 .unwrap_or_default();
640 if retval_in_reply_msg {
641 writeln!(
642 self.output_file,
643 " let mut reply = match H::{}(vm, mp) {{",
644 service.caller()
645 )?;
646 writeln!(self.output_file, " Ok(reply) => reply,")?;
647 writeln!(
648 self.output_file,
649 " Err(retval) => {} {{",
650 to_upper_camel_case(service.reply())
651 )?;
652 writeln!(self.output_file, " retval,")?;
653 writeln!(self.output_file, " ..Default::default()")?;
654 writeln!(self.output_file, " }}")?;
655 writeln!(self.output_file, " .into(),")?;
656 writeln!(self.output_file, " }};")?;
657 } else {
658 writeln!(
659 self.output_file,
660 " let mut reply = H::{}(vm, mp);",
661 service.caller()
662 )?;
663 }
664 writeln!(
665 self.output_file,
666 " ::vpp_plugin::vlibapi::registration_scope(|s| {{"
667 )?;
668 writeln!(
671 self.output_file,
672 " if let Some(reg) = s.from_client_index(vm, mp.client_index) {{"
673 )?;
674 writeln!(self.output_file, " reply.context = mp.context;",)?;
675 writeln!(
676 self.output_file,
677 " {}_endian(::std::ptr::addr_of_mut!(*reply), true);",
678 service.reply()
679 )?;
680 writeln!(self.output_file, " reg.send_message(reply);")?;
681 writeln!(self.output_file, " }}")?;
682 writeln!(self.output_file, " }})")?;
683 }
684 writeln!(self.output_file, "}}")?;
685 writeln!(self.output_file)?;
686 }
687
688 writeln!(
689 self.output_file,
690 "pub const MESSAGE_COUNT: u16 = {};",
691 self.parser.messages().len()
692 )?;
693 writeln!(self.output_file)?;
694
695 writeln!(
696 self.output_file,
697 "static MSG_ID_BASE: ::std::sync::atomic::AtomicU16 = ::std::sync::atomic::AtomicU16::new(0);"
698 )?;
699 writeln!(self.output_file)?;
700 writeln!(self.output_file, "pub fn msg_id_base() -> u16 {{")?;
701 writeln!(
702 self.output_file,
703 " MSG_ID_BASE.load(::std::sync::atomic::Ordering::Relaxed)"
704 )?;
705 writeln!(self.output_file, "}}")?;
706 writeln!(self.output_file)?;
707
708 writeln!(
709 self.output_file,
710 "pub fn {}_register_messages<H: Handlers>() {{",
711 self.module
712 )?;
713 writeln!(self.output_file, " unsafe {{")?;
714 writeln!(
715 self.output_file,
716 " let am = ::vpp_plugin::bindings::vlibapi_helper_get_main();"
717 )?;
718 writeln!(
719 self.output_file,
720 " let mut json_api_repr = ::vpp_plugin::vppinfra::vec::Vec::from_raw((*am).json_api_repr);"
721 )?;
722 writeln!(self.output_file, " json_api_repr.push(",)?;
723 writeln!(
724 self.output_file,
725 " concat!(include_str!(\"{}.api.json\"), \"\\0\")",
726 self.module
727 )?;
728 writeln!(self.output_file, " .as_ptr()",)?;
729 writeln!(self.output_file, " .cast_mut(),",)?;
730 writeln!(self.output_file, " );",)?;
731 writeln!(
732 self.output_file,
733 " (*am).json_api_repr = json_api_repr.into_raw();"
734 )?;
735 writeln!(self.output_file)?;
736 writeln!(
737 self.output_file,
738 " let msg_id_base = ::vpp_plugin::bindings::vl_msg_api_get_msg_ids(",
739 )?;
740 writeln!(
741 self.output_file,
742 " c\"{}_{:08x}\".as_ptr() as *mut ::std::os::raw::c_char,",
743 self.module,
744 self.parser.file_crc()
745 )?;
746 writeln!(self.output_file, " MESSAGE_COUNT as i32,",)?;
747 writeln!(self.output_file, " );",)?;
748 writeln!(self.output_file)?;
749 for message in self.parser.messages() {
750 writeln!(
751 self.output_file,
752 " ::vpp_plugin::bindings::vl_msg_api_add_msg_name_crc("
753 )?;
754 writeln!(self.output_file, " am,")?;
755 writeln!(
756 self.output_file,
757 " c\"{}_{:08x}\".as_ptr() as *mut ::std::os::raw::c_char,",
758 message.name(),
759 message.crc()
760 )?;
761 writeln!(
762 self.output_file,
763 " {}::MSG_ID as u32 + msg_id_base as u32,",
764 to_upper_camel_case(message.name()),
765 )?;
766 writeln!(self.output_file, " );")?;
767 writeln!(self.output_file)?;
768 }
769 for service in self.parser.services() {
770 let caller = self.parser.message(service.caller()).unwrap();
771 let caller_upper_camel = to_upper_camel_case(service.caller());
772 writeln!(
773 self.output_file,
774 " let mut c = vpp_plugin::bindings::vl_msg_api_msg_config_t {{"
775 )?;
776 writeln!(
777 self.output_file,
778 " id: {}::MSG_ID as i32 + msg_id_base as i32,",
779 caller_upper_camel,
780 )?;
781 writeln!(
782 self.output_file,
783 " name: c\"{}\".as_ptr() as *mut ::std::os::raw::c_char,",
784 service.caller()
785 )?;
786 writeln!(
787 self.output_file,
788 " handler: {}_handler_raw::<H> as *mut ::std::os::raw::c_void,",
789 service.caller()
790 )?;
791 writeln!(
792 self.output_file,
793 " endian: {}_endian as *mut ::std::os::raw::c_void,",
794 service.caller()
795 )?;
796 writeln!(
797 self.output_file,
798 " format_fn: {}_format as *mut ::std::os::raw::c_void,",
799 service.caller()
800 )?;
801 writeln!(
802 self.output_file,
803 " tojson: std::ptr::null_mut(),"
804 )?;
805 writeln!(
806 self.output_file,
807 " fromjson: std::ptr::null_mut(),"
808 )?;
809 writeln!(
810 self.output_file,
811 " calc_size: {}_calc_size as *mut ::std::os::raw::c_void,",
812 service.caller()
813 )?;
814 writeln!(self.output_file, " ..Default::default()")?;
815 writeln!(self.output_file, " }};")?;
816 writeln!(self.output_file, " c.set_traced(1);")?;
817 writeln!(self.output_file, " c.set_replay(1);")?;
818 if caller.auto_endian() {
820 writeln!(self.output_file, " c.set_is_autoendian(1);")?;
821 }
822 writeln!(
823 self.output_file,
824 " ::vpp_plugin::bindings::vl_msg_api_config(std::ptr::addr_of_mut!(c));"
825 )?;
826 writeln!(self.output_file)?;
827
828 if service.reply() != "null" {
829 let reply = self.parser.message(service.reply()).unwrap();
830 let reply_upper_camel = to_upper_camel_case(service.reply());
831 writeln!(
832 self.output_file,
833 " let mut c = vpp_plugin::bindings::vl_msg_api_msg_config_t {{"
834 )?;
835 writeln!(
836 self.output_file,
837 " id: {}::MSG_ID as i32 + msg_id_base as i32,",
838 reply_upper_camel
839 )?;
840 writeln!(
841 self.output_file,
842 " name: c\"{}\".as_ptr() as *mut ::std::os::raw::c_char,",
843 service.reply()
844 )?;
845 writeln!(
846 self.output_file,
847 " handler: ::std::ptr::null_mut(),"
848 )?;
849 writeln!(
850 self.output_file,
851 " endian: {}_endian as *mut ::std::os::raw::c_void,",
852 service.reply()
853 )?;
854 writeln!(
855 self.output_file,
856 " format_fn: {}_format as *mut ::std::os::raw::c_void,",
857 service.reply()
858 )?;
859 writeln!(
860 self.output_file,
861 " tojson: std::ptr::null_mut(),"
862 )?;
863 writeln!(
864 self.output_file,
865 " fromjson: std::ptr::null_mut(),"
866 )?;
867 writeln!(
868 self.output_file,
869 " calc_size: {}_calc_size as *mut ::std::os::raw::c_void,",
870 service.reply()
871 )?;
872 writeln!(self.output_file, " ..Default::default()")?;
873 writeln!(self.output_file, " }};")?;
874 writeln!(self.output_file, " c.set_traced(1);")?;
875 writeln!(self.output_file, " c.set_replay(1);")?;
876 if reply.auto_endian() {
878 writeln!(self.output_file, " c.set_is_autoendian(1);")?;
879 }
880 writeln!(
881 self.output_file,
882 " ::vpp_plugin::bindings::vl_msg_api_config(std::ptr::addr_of_mut!(c));"
883 )?;
884 writeln!(self.output_file)?;
885 }
886
887 if let Some(stream_message_name) = service.stream_message() {
888 let stream_message = self.parser.message(stream_message_name).unwrap();
889 let stream_message_upper_camel = to_upper_camel_case(stream_message_name);
890 writeln!(
891 self.output_file,
892 " let mut c = vpp_plugin::bindings::vl_msg_api_msg_config_t {{"
893 )?;
894 writeln!(
895 self.output_file,
896 " id: {}::MSG_ID as i32 + msg_id_base as i32,",
897 stream_message_upper_camel
898 )?;
899 writeln!(
900 self.output_file,
901 " name: c\"{}\".as_ptr() as *mut ::std::os::raw::c_char,",
902 stream_message_name
903 )?;
904 writeln!(
905 self.output_file,
906 " handler: ::std::ptr::null_mut(),"
907 )?;
908 writeln!(
909 self.output_file,
910 " endian: {}_endian as *mut ::std::os::raw::c_void,",
911 stream_message_name
912 )?;
913 writeln!(
914 self.output_file,
915 " format_fn: {}_format as *mut ::std::os::raw::c_void,",
916 stream_message_name
917 )?;
918 writeln!(
919 self.output_file,
920 " tojson: std::ptr::null_mut(),"
921 )?;
922 writeln!(
923 self.output_file,
924 " fromjson: std::ptr::null_mut(),"
925 )?;
926 writeln!(
927 self.output_file,
928 " calc_size: {}_calc_size as *mut ::std::os::raw::c_void,",
929 stream_message_name
930 )?;
931 writeln!(self.output_file, " ..Default::default()")?;
932 writeln!(self.output_file, " }};")?;
933 writeln!(self.output_file, " c.set_traced(1);")?;
934 writeln!(self.output_file, " c.set_replay(1);")?;
935 if stream_message.auto_endian() {
937 writeln!(self.output_file, " c.set_is_autoendian(1);")?;
938 }
939 writeln!(
940 self.output_file,
941 " ::vpp_plugin::bindings::vl_msg_api_config(std::ptr::addr_of_mut!(c));"
942 )?;
943 writeln!(self.output_file)?;
944 }
945 }
946
947 writeln!(
948 self.output_file,
949 " MSG_ID_BASE.store(msg_id_base, ::std::sync::atomic::Ordering::Relaxed);"
950 )?;
951 writeln!(self.output_file, " }}")?;
952 writeln!(self.output_file, "}}")?;
953
954 Ok(())
955 }
956
957 fn generate(mut self) -> Result<(), Error> {
958 self.output_json_file
959 .write_all(generate_json(self.parser)?.as_bytes())?;
960 self.generate_aliases()?;
961 self.generate_enums()?;
962 self.generate_unions()?;
963 self.generate_types()?;
964 self.generate_messages()?;
965 self.generate_register()?;
966 Ok(())
967 }
968}