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::{
63 Alias, ApiParser, CountDescriptor, Enum, Field, FieldSize, Message, Type, Union,
64 VL_API_PREFIX, VL_API_SUFFIX,
65 },
66};
67
68mod json;
69mod parser;
70
71#[derive(Debug, Error)]
73#[non_exhaustive]
74pub enum Error {
75 #[error("Parser error")]
77 Parser(#[from] parser::Error),
78 #[error("I/O error")]
80 Io(#[from] std::io::Error),
81 #[error("Failed to generate JSON")]
83 Json(#[from] serde_json::Error),
84 #[error("{0}")]
86 Unimplemented(String),
87}
88
89fn to_upper_camel_case(s: &str) -> String {
90 s.split('_')
91 .flat_map(|word| {
92 let word = word.to_ascii_lowercase();
93 let mut chars = word.chars();
94 let capital = chars.next().map(|x| x.to_ascii_uppercase());
95 capital.into_iter().chain(chars).collect::<Vec<_>>()
96 })
97 .collect()
98}
99
100trait ApiParserRustExt {
101 fn to_rust_type(&self, r#type: &str) -> Result<String, Error>;
102 fn to_rust_vla_elem_type(&self, r#type: &str) -> Result<String, Error>;
103}
104
105impl ApiParserRustExt for ApiParser {
106 fn to_rust_type(&self, r#type: &str) -> Result<String, Error> {
107 Ok(
108 if let Some(t) = r#type.strip_prefix(VL_API_PREFIX)
109 && let Some(t) = t.strip_suffix(VL_API_SUFFIX)
110 {
111 let global_type = self.lookup_global_type(t)?;
112 if let Some(import_module) = global_type.import_module() {
113 format!("super::{}_api::{}", import_module, to_upper_camel_case(t))
114 } else {
115 to_upper_camel_case(t)
116 }
117 } else {
118 r#type.to_string()
119 },
120 )
121 }
122
123 fn to_rust_vla_elem_type(&self, r#type: &str) -> Result<String, Error> {
124 Ok(match r#type {
125 "u16" | "i16" | "u32" | "i32" | "u64" | "i64" | "f64" => {
127 format!(
128 "::vpp_plugin::vlibapi::num_unaligned::Unaligned{}",
129 to_upper_camel_case(r#type)
130 )
131 }
132 _ => self.to_rust_type(r#type)?,
133 })
134 }
135}
136
137#[derive(Debug)]
161pub struct Builder {
162 parser: ApiParser,
163
164 module: String,
165 output_file: File,
166 output_json_file: File,
167}
168
169impl Builder {
170 pub fn new(input_file: &str, output_dir: &str) -> Result<Self, Error> {
175 let in_build_script = env::var("OUT_DIR").is_ok() && env::var("CARGO_MANIFEST_DIR").is_ok();
176 if in_build_script {
177 println!("cargo:cargo-rerun-if-changed={}", input_file);
178 }
179
180 let input_file_name = Path::new(input_file).iter().next_back().unwrap();
182 let module = Path::new(input_file_name)
183 .file_stem()
184 .unwrap()
185 .to_string_lossy()
186 .to_string();
187
188 DirBuilder::new().recursive(true).create(output_dir)?;
189 let output_file = Path::new(output_dir).join(format!("{}_api.rs", module));
190 let output_json_file = Path::new(output_dir).join(format!("{}.api.json", module));
191
192 let parser = ApiParser::new(input_file)?;
193
194 if in_build_script {
195 for import in parser.imports() {
196 println!("cargo:cargo-rerun-if-changed={}", import);
197 }
198 }
199
200 Ok(Self {
201 parser,
202 module,
203 output_file: File::create(&output_file)?,
204 output_json_file: File::create(&output_json_file)?,
205 })
206 }
207
208 pub fn generate(self) -> Result<(), Error> {
213 ApiGenContext {
214 parser: &self.parser,
215 module: self.module,
216 output_file: self.output_file,
217 output_json_file: self.output_json_file,
218 }
219 .generate()
220 }
221}
222
223enum EndianSwapInput<'a> {
224 Fields(&'a [Field]),
225 Alias(&'a Field),
226}
227
228struct ApiGenContext<'a> {
233 parser: &'a ApiParser,
234
235 module: String,
236 output_file: File,
237 output_json_file: File,
238}
239
240impl ApiGenContext<'_> {
241 fn generate_field(&mut self, field: &Field) -> Result<(), Error> {
242 if field.r#type == "string" {
243 match &field.size {
244 Some(FieldSize::Fixed(size)) => {
245 writeln!(
246 self.output_file,
247 " pub {}: ::vpp_plugin::vlibapi::ApiFixedString<{}>,",
248 field.name, size,
249 )?;
250 return Ok(());
251 }
252 Some(FieldSize::Variable(None)) => {
253 writeln!(
254 self.output_file,
255 " pub {}: ::vpp_plugin::vlibapi::ApiString,",
256 field.name,
257 )?;
258 return Ok(());
259 }
260 _ => {}
261 }
262 }
263
264 match &field.size {
265 Some(FieldSize::Fixed(size)) => {
266 writeln!(
267 self.output_file,
268 " pub {}: [{}; {}],",
269 field.name,
270 self.parser.to_rust_type(&field.r#type)?,
271 size,
272 )?;
273 }
274 Some(FieldSize::Variable(_)) => {
275 writeln!(
276 self.output_file,
277 " pub {}: [{}; 0],",
278 field.name,
279 self.parser.to_rust_vla_elem_type(&field.r#type)?,
280 )?;
281 }
282 None => {
283 writeln!(
284 self.output_file,
285 " pub {}: {},",
286 field.name,
287 self.parser.to_rust_type(&field.r#type)?,
288 )?;
289 }
290 }
291 Ok(())
292 }
293
294 fn generate_debug_trait(&mut self, name: &str, fields: &[Field]) -> Result<(), Error> {
295 let upper_camel_name = to_upper_camel_case(name);
296
297 writeln!(
298 self.output_file,
299 "impl ::std::fmt::Debug for {} {{",
300 upper_camel_name
301 )?;
302 writeln!(self.output_file, " #[allow(non_snake_case)]")?;
304 writeln!(
305 self.output_file,
306 " fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {{"
307 )?;
308 for field in fields {
309 if !matches!(field.size, Some(FieldSize::Variable(_))) {
310 writeln!(
311 self.output_file,
312 " let tmp_{} = self.{};",
313 field.name, field.name
314 )?;
315 }
316 }
317 writeln!(
318 self.output_file,
319 " f.debug_struct(\"{}\")",
320 upper_camel_name
321 )?;
322 for field in fields {
323 if !matches!(field.size, Some(FieldSize::Variable(_))) {
324 writeln!(
325 self.output_file,
326 " .field(\"{}\", &tmp_{})",
327 field.name, field.name
328 )?;
329 }
330 }
331 writeln!(self.output_file, " .finish_non_exhaustive()")?;
332 writeln!(self.output_file, " }}")?;
333 writeln!(self.output_file, "}}")?;
334 writeln!(self.output_file)?;
335
336 Ok(())
337 }
338
339 fn generate_vla_accessors(&mut self, count_field: &str, field: &Field) -> Result<(), Error> {
340 let vla_elem_type = self.parser.to_rust_vla_elem_type(&field.r#type)?;
341 writeln!(self.output_file, " #[allow(dead_code)]")?;
342 writeln!(
343 self.output_file,
344 " pub unsafe fn {}(&self) -> &[{}] {{",
345 field.name, vla_elem_type
346 )?;
347 writeln!(self.output_file, " unsafe {{",)?;
348 writeln!(
349 self.output_file,
350 " ::std::slice::from_raw_parts(std::ptr::addr_of!(self.{}).cast(), self.{} as usize)",
351 field.name, count_field
352 )?;
353 writeln!(self.output_file, " }}",)?;
354 writeln!(self.output_file, " }}")?;
355 writeln!(self.output_file)?;
356 writeln!(self.output_file, " #[allow(dead_code)]")?;
357 writeln!(
358 self.output_file,
359 " pub unsafe fn {}_mut(&mut self) -> &mut [{}] {{",
360 field.name, vla_elem_type
361 )?;
362 writeln!(self.output_file, " unsafe {{",)?;
363 writeln!(
364 self.output_file,
365 " std::slice::from_raw_parts_mut(std::ptr::addr_of_mut!(self.{}).cast(), self.{} as usize)",
366 field.name, count_field
367 )?;
368 writeln!(self.output_file, " }}",)?;
369 writeln!(self.output_file, " }}")?;
370
371 Ok(())
372 }
373
374 fn generate_message(&mut self, id: usize, message: &Message) -> Result<(), Error> {
375 let upper_camel_name = to_upper_camel_case(message.name());
376
377 if let Some(comment) = message.comment() {
378 writeln!(
379 self.output_file,
380 "#[doc = \"{}\"]",
381 comment.replace("\"", "\\\"")
382 )?;
383 }
384 let opt_derives = if message.manual_print() || message.vla_non_recursive().is_some() {
385 ""
386 } else if message.vla(self.parser).is_some() {
387 "Debug, "
388 } else {
389 "Debug, PartialEq, "
390 };
391 writeln!(self.output_file, "#[derive({}Copy, Clone)]", opt_derives)?;
392 writeln!(self.output_file, "#[repr(C, packed)]")?;
393 writeln!(self.output_file, "pub struct {} {{", upper_camel_name)?;
394 for field in message.fields() {
395 self.generate_field(field)?;
396 }
397 writeln!(self.output_file, "}}")?;
398 writeln!(self.output_file)?;
399
400 writeln!(self.output_file, "impl {} {{", upper_camel_name)?;
401 writeln!(self.output_file, " pub const MSG_ID: u16 = {};", id)?;
402 writeln!(self.output_file)?;
403 writeln!(self.output_file, " pub fn msg_id() -> u16 {{")?;
404 writeln!(self.output_file, " msg_id_base() + Self::MSG_ID")?;
405 writeln!(self.output_file, " }}")?;
406 if let Some((field, count_descr)) = message.vla(self.parser) {
407 writeln!(self.output_file)?;
408 if let Some(FieldSize::Variable(Some(count_field))) = &field.size {
409 self.generate_vla_accessors(count_field, field)?;
410 writeln!(self.output_file)?;
411 }
412 writeln!(self.output_file, " #[allow(dead_code)]")?;
413 match count_descr {
414 CountDescriptor::Field { path, r#type } => {
415 let var_name = path.last().cloned().unwrap_or_default();
416 writeln!(
417 self.output_file,
418 " pub fn new_message({}: {}) -> ::vpp_plugin::vlibapi::Message<Self> {{",
419 var_name, r#type
420 )?;
421 let count_expr = if r#type == "u32" {
423 var_name.clone()
424 } else {
425 format!("{} as u32", var_name)
426 };
427 writeln!(
428 self.output_file,
429 " let size = ::std::mem::size_of::<Self>() as u32 + {} * ::std::mem::size_of::<{}>() as u32;",
430 count_expr,
431 self.parser.to_rust_type(&field.r#type)?,
432 )?;
433 writeln!(
434 self.output_file,
435 " let mut message = unsafe {{ ::std::mem::transmute::<::vpp_plugin::vlibapi::Message<u8>, ::vpp_plugin::vlibapi::Message<Self>>(::vpp_plugin::vlibapi::Message::new_bytes(size)) }};",
436 )?;
437 writeln!(
438 self.output_file,
439 " message._vl_msg_id = Self::msg_id();",
440 )?;
441 writeln!(
442 self.output_file,
443 " message.{} = {};",
444 path.join("."),
445 var_name,
446 )?;
447 }
448 CountDescriptor::String(path) => {
449 writeln!(
450 self.output_file,
451 " pub fn new_message(length: u32) -> ::vpp_plugin::vlibapi::Message<Self> {{",
452 )?;
453 writeln!(
454 self.output_file,
455 " let size = ::std::mem::size_of::<Self>() as u32 + length;",
456 )?;
457 writeln!(
458 self.output_file,
459 " let mut message = unsafe {{ ::std::mem::transmute::<::vpp_plugin::vlibapi::Message<u8>, ::vpp_plugin::vlibapi::Message<Self>>(::vpp_plugin::vlibapi::Message::new_bytes(size)) }};",
460 )?;
461 writeln!(
462 self.output_file,
463 " message._vl_msg_id = Self::msg_id();",
464 )?;
465 writeln!(
466 self.output_file,
467 " unsafe {{ message.{}.set_len(length); }}",
468 path.join("."),
469 )?;
470 }
471 }
472 writeln!(self.output_file, " message",)?;
473 writeln!(self.output_file, " }}")?;
474 writeln!(self.output_file)?;
475 }
476 writeln!(self.output_file, "}}")?;
477 writeln!(self.output_file)?;
478
479 writeln!(self.output_file, "impl Default for {} {{", upper_camel_name)?;
480 writeln!(self.output_file, " fn default() -> Self {{")?;
481 writeln!(self.output_file, " Self {{")?;
482 for field in message.fields() {
483 if field.name == "_vl_msg_id" {
484 writeln!(self.output_file, " _vl_msg_id: Self::msg_id(),")?;
485 } else {
486 writeln!(
487 self.output_file,
488 " {}: Default::default(),",
489 field.name,
490 )?;
491 }
492 }
493 writeln!(self.output_file, " }}")?;
494 writeln!(self.output_file, " }}")?;
495 writeln!(self.output_file, "}}")?;
496 writeln!(self.output_file)?;
497
498 self.generate_endian_swap(message.name(), EndianSwapInput::Fields(message.fields()))?;
499
500 if message.vla_non_recursive().is_some() {
503 self.generate_debug_trait(message.name(), message.fields())?;
504 }
505
506 writeln!(
507 self.output_file,
508 "unsafe extern \"C\" fn {}_endian(a: *mut {}, to_net: bool) {{",
509 message.name(),
510 upper_camel_name
511 )?;
512 writeln!(self.output_file, " unsafe {{")?;
513 writeln!(
514 self.output_file,
515 " ::vpp_plugin::vlibapi::EndianSwap::endian_swap(&mut *a, to_net);"
516 )?;
517 writeln!(self.output_file, " }}")?;
518 writeln!(self.output_file, "}}")?;
519 writeln!(self.output_file)?;
520
521 writeln!(
522 self.output_file,
523 "unsafe extern \"C\" fn {}_format(s: *mut u8, args: *mut ::vpp_plugin::bindings::va_list) -> *mut u8 {{",
524 message.name()
525 )?;
526 writeln!(self.output_file, " unsafe {{")?;
527 writeln!(
528 self.output_file,
529 " let mut args = ::std::mem::transmute::<*mut ::vpp_plugin::bindings::va_list, ::vpp_plugin::macro_support::va_list::VaList<'_>>(args);"
530 )?;
531 writeln!(
532 self.output_file,
533 " let t = args.get::<*const {}>();",
534 upper_camel_name
535 )?;
536 writeln!(
537 self.output_file,
538 " let mut s = ::vpp_plugin::vppinfra::vec::Vec::from_raw(s);"
539 )?;
540 writeln!(
541 self.output_file,
542 " s.extend(format!(\"{{:?}}\", &*t).as_bytes());"
543 )?;
544 writeln!(self.output_file, " s.into_raw()")?;
545 writeln!(self.output_file, " }}")?;
546 writeln!(self.output_file, "}}")?;
547 writeln!(self.output_file)?;
548 if let Some((field, count_descr)) = message.vla(self.parser) {
549 write!(self.output_file, "pub ",)?;
550 writeln!(
551 self.output_file,
552 "unsafe extern \"C\" fn {}_calc_size(a: *mut {}) -> ::vpp_plugin::bindings::uword {{",
553 message.name(),
554 upper_camel_name
555 )?;
556 writeln!(self.output_file, " unsafe {{")?;
557 write!(
558 self.output_file,
559 " ::std::mem::size_of::<{}>() as ::vpp_plugin::bindings::uword",
560 upper_camel_name,
561 )?;
562 match count_descr {
563 CountDescriptor::Field {
564 path: count_path,
565 r#type: count_type,
566 } => match count_type.as_str() {
567 "u8" => {
568 writeln!(
569 self.output_file,
570 " + (*a).{} as ::vpp_plugin::bindings::uword * ::std::mem::size_of::<{}>() as ::vpp_plugin::bindings::uword",
571 count_path.join("."),
572 self.parser.to_rust_type(&field.r#type)?,
573 )?;
574 }
575 "u16" | "u32" | "u64" | "i16" | "i32" | "i64" => {
576 writeln!(
577 self.output_file,
578 " + {}::from_be((*a).{}) as ::vpp_plugin::bindings::uword * ::std::mem::size_of::<{}>() as ::vpp_plugin::bindings::uword",
579 self.parser.to_rust_type(&count_type)?,
580 count_path.join("."),
581 self.parser.to_rust_type(&field.r#type)?,
582 )?;
583 }
584 _ => {
585 return Err(Error::Unimplemented(format!(
586 "Unexpected type of variable-length array count field {} in message {}",
587 count_path.join("."),
588 message.name()
589 )));
590 }
591 },
592 CountDescriptor::String(string_path) => {
593 writeln!(
594 self.output_file,
595 " + u32::from_be((*a).{}.len()) as ::vpp_plugin::bindings::uword",
596 string_path.join("."),
597 )?;
598 }
599 }
600 writeln!(self.output_file, " }}")?;
601 } else {
602 writeln!(
603 self.output_file,
604 "unsafe extern \"C\" fn {}_calc_size(_a: *mut {}) -> ::vpp_plugin::bindings::uword {{",
605 message.name(),
606 upper_camel_name
607 )?;
608 writeln!(
609 self.output_file,
610 " ::std::mem::size_of::<{}>() as ::vpp_plugin::bindings::uword",
611 upper_camel_name
612 )?;
613 }
614 writeln!(self.output_file, "}}")?;
615 writeln!(self.output_file)?;
616 Ok(())
617 }
618
619 fn generate_messages(&mut self) -> Result<(), Error> {
620 for (id, message) in self.parser.messages().iter().enumerate() {
621 self.generate_message(id, message)?;
622 }
623 Ok(())
624 }
625
626 fn generate_alias(&mut self, alias: &Alias) -> Result<(), Error> {
627 let upper_camel_name = to_upper_camel_case(&alias.field().name);
628
629 let opt_derives = if alias.manual_print() {
630 ""
631 } else {
632 "Debug, PartialEq, Default, "
633 };
634 writeln!(self.output_file, "#[derive({}Copy, Clone)]", opt_derives)?;
635 writeln!(self.output_file, "#[repr(C, packed)]")?;
636 if let Some(FieldSize::Fixed(length)) = alias.field().size {
637 writeln!(
638 self.output_file,
639 "pub struct {}(pub[{}; {}]);",
640 upper_camel_name,
641 self.parser.to_rust_type(&alias.field().r#type)?,
642 length
643 )?;
644 } else {
645 writeln!(
646 self.output_file,
647 "pub struct {}(pub {});",
648 upper_camel_name,
649 self.parser.to_rust_type(&alias.field().r#type)?
650 )?;
651 }
652 if !alias.manual_endian() {
653 self.generate_endian_swap(&alias.field().name, EndianSwapInput::Alias(alias.field()))?;
654 }
655
656 Ok(())
657 }
658
659 fn generate_aliases(&mut self) -> Result<(), Error> {
660 for message in self.parser.aliases() {
661 self.generate_alias(message)?;
662 }
663 Ok(())
664 }
665
666 fn generate_enum(&mut self, e: &Enum) -> Result<(), Error> {
667 let upper_camel_name = to_upper_camel_case(&e.name);
668
669 writeln!(
678 self.output_file,
679 "#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]",
680 )?;
681 writeln!(self.output_file, "#[repr(C, packed)]")?;
682 writeln!(
683 self.output_file,
684 "pub struct {}(pub {});",
685 upper_camel_name, &e.size,
686 )?;
687
688 writeln!(self.output_file)?;
689
690 for variant in &e.variants {
691 writeln!(
692 self.output_file,
693 "pub const {}: {} = {}({});",
694 variant.id, upper_camel_name, upper_camel_name, variant.value,
695 )?;
696 }
697 if !e.variants.is_empty() {
698 writeln!(self.output_file)?;
699 }
700
701 writeln!(
702 self.output_file,
703 "impl ::std::fmt::Debug for {} {{",
704 upper_camel_name
705 )?;
706 writeln!(
707 self.output_file,
708 " fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {{"
709 )?;
710 writeln!(self.output_file, " match *self {{")?;
711 for variant in &e.variants {
712 writeln!(
713 self.output_file,
714 " {} => f.write_str(\"{}\"),",
715 variant.id, variant.id,
716 )?;
717 }
718 writeln!(self.output_file, " _ => {{")?;
719 writeln!(self.output_file, " let tmp = self.0;")?;
720 writeln!(self.output_file, " tmp.fmt(f)")?;
721 writeln!(self.output_file, " }}")?;
722 writeln!(self.output_file, " }}")?;
723 writeln!(self.output_file, " }}")?;
724 writeln!(self.output_file, "}}")?;
725 writeln!(self.output_file)?;
726
727 writeln!(
728 self.output_file,
729 "impl ::vpp_plugin::vlibapi::EndianSwap for {} {{",
730 upper_camel_name
731 )?;
732 writeln!(
733 self.output_file,
734 " unsafe fn endian_swap(&mut self, to_net: bool) {{",
735 )?;
736 writeln!(self.output_file, " let _ = to_net;",)?;
738 match e.size.as_str() {
739 "u8" => {
740 writeln!(self.output_file, " // *self = Self(self.0) (no-op)",)?;
741 }
742 "u16" | "u32" | "u64" | "i16" | "i32" | "i64" => {
743 writeln!(self.output_file, " *self = Self(self.0.to_be());",)?;
744 }
745 _ => {
746 return Err(Error::Unimplemented(format!(
747 "Unexpected size type {} for enum {}",
748 e.size, e.name
749 )));
750 }
751 }
752 writeln!(self.output_file, " }}",)?;
753 writeln!(self.output_file, "}}")?;
754 writeln!(self.output_file)?;
755
756 Ok(())
757 }
758
759 fn generate_enumflag(&mut self, e: &Enum) -> Result<(), Error> {
760 let upper_camel_name = to_upper_camel_case(&e.name);
761
762 writeln!(
763 self.output_file,
764 "#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]",
765 )?;
766 writeln!(self.output_file, "#[repr(C, packed)]")?;
767 writeln!(
768 self.output_file,
769 "pub struct {}({});",
770 upper_camel_name, &e.size,
771 )?;
772 writeln!(self.output_file)?;
773 writeln!(self.output_file, "::vpp_plugin::bitflags::bitflags! {{",)?;
774 writeln!(
775 self.output_file,
776 " impl {}: {} {{",
777 upper_camel_name, &e.size,
778 )?;
779
780 let upper_name = format!("{}_", e.name.to_uppercase());
781 for variant in &e.variants {
782 let id = variant
786 .id
787 .strip_prefix(&upper_name)
788 .unwrap_or(variant.id.as_str());
789 writeln!(
790 self.output_file,
791 " const {} = {};",
792 id, variant.value,
793 )?;
794 }
795 writeln!(self.output_file, " }}")?;
796 writeln!(self.output_file, "}}")?;
797 writeln!(self.output_file)?;
798
799 writeln!(
800 self.output_file,
801 "impl ::std::fmt::Debug for {} {{",
802 upper_camel_name
803 )?;
804 writeln!(
805 self.output_file,
806 " fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {{"
807 )?;
808 writeln!(
809 self.output_file,
810 " ::vpp_plugin::bitflags::parser::to_writer(self, f)"
811 )?;
812 writeln!(self.output_file, " }}")?;
813 writeln!(self.output_file, "}}")?;
814 writeln!(self.output_file)?;
815
816 writeln!(
817 self.output_file,
818 "impl ::vpp_plugin::vlibapi::EndianSwap for {} {{",
819 upper_camel_name
820 )?;
821 writeln!(
822 self.output_file,
823 " unsafe fn endian_swap(&mut self, to_net: bool) {{",
824 )?;
825 writeln!(self.output_file, " let _ = to_net;",)?;
827 match e.size.as_str() {
828 "u8" => {
829 writeln!(
830 self.output_file,
831 " // *self = Self::from_bits_retain(self.bits()) (no-op)",
832 )?;
833 }
834 "u16" | "u32" | "u64" | "i16" | "i32" | "i64" => {
835 writeln!(
836 self.output_file,
837 " *self = Self::from_bits_retain(self.bits().to_be());",
838 )?;
839 }
840 _ => {
841 return Err(Error::Unimplemented(format!(
842 "Unexpected size type {} for enum {}",
843 e.size, e.name
844 )));
845 }
846 }
847 writeln!(self.output_file, " }}",)?;
848 writeln!(self.output_file, "}}")?;
849 writeln!(self.output_file)?;
850
851 Ok(())
852 }
853
854 fn generate_enums(&mut self) -> Result<(), Error> {
855 for e in self.parser.enums() {
856 self.generate_enum(e)?;
857 }
858 for e in self.parser.enumflags() {
859 self.generate_enumflag(e)?;
860 }
861 Ok(())
862 }
863
864 fn generate_union(&mut self, un: &Union) -> Result<(), Error> {
865 let upper_camel_name = to_upper_camel_case(un.name());
866
867 if let Some(comment) = un.comment() {
868 writeln!(
869 self.output_file,
870 "#[doc = \"{}\"]",
871 comment.replace("\"", "\\\"")
872 )?;
873 }
874 writeln!(self.output_file, "#[derive(Copy, Clone)]",)?;
875 writeln!(self.output_file, "#[repr(C, packed)]")?;
876 writeln!(self.output_file, "pub union {} {{", upper_camel_name)?;
877 for field in un.fields() {
878 self.generate_field(field)?;
879 }
880 writeln!(self.output_file, "}}")?;
881 writeln!(self.output_file)?;
882 Ok(())
887 }
888
889 fn generate_unions(&mut self) -> Result<(), Error> {
890 for un in self.parser.unions() {
891 self.generate_union(un)?;
892 }
893 Ok(())
894 }
895
896 fn generate_endian_swap(&mut self, name: &str, input: EndianSwapInput) -> Result<(), Error> {
897 writeln!(
898 self.output_file,
899 "impl ::vpp_plugin::vlibapi::EndianSwap for {} {{",
900 to_upper_camel_case(name)
901 )?;
902 writeln!(
903 self.output_file,
904 " unsafe fn endian_swap(&mut self, to_net: bool) {{",
905 )?;
906 writeln!(self.output_file, " let _ = to_net;")?;
908 writeln!(self.output_file, " #[allow(unused_unsafe)]")?;
910 writeln!(self.output_file, " unsafe {{")?;
911 let fields = match input {
912 EndianSwapInput::Fields(fields) => fields,
913 EndianSwapInput::Alias(field) => std::slice::from_ref(field),
914 };
915 for field in fields {
916 let field_name = match input {
917 EndianSwapInput::Fields(_) => &field.name,
918 EndianSwapInput::Alias(_) => "0",
919 };
920
921 let mut gen_count_variable = |count_field| {
922 let count_field = fields
923 .iter()
924 .find(|field| &field.name == count_field)
925 .ok_or_else(|| {
926 Error::Unimplemented(format!(
927 "Unable to find variable count field {}",
928 count_field
929 ))
930 })?;
931 let vla_elem_type = self.parser.to_rust_vla_elem_type(&field.r#type)?;
932 writeln!(self.output_file, " let count = if to_net {{",)?;
933 writeln!(
934 self.output_file,
935 " {}::from_be(self.{})",
936 count_field.r#type, count_field.name,
937 )?;
938 writeln!(self.output_file, " }} else {{",)?;
939 writeln!(
940 self.output_file,
941 " self.{}",
942 count_field.name,
943 )?;
944 writeln!(self.output_file, " }};",)?;
945 writeln!(
946 self.output_file,
947 " let array = ::std::slice::from_raw_parts_mut(std::ptr::addr_of_mut!(self.{}) as *mut {}, count as usize);",
948 field_name, vla_elem_type,
949 )?;
950 Ok::<_, Error>(())
951 };
952
953 match field.r#type.as_str() {
954 "u8" | "bool" => {
955 writeln!(
956 self.output_file,
957 " // self.{} = self.{} (no-op)",
958 field_name, field_name
959 )?;
960 }
961 "string" => {
962 writeln!(
963 self.output_file,
964 " ::vpp_plugin::vlibapi::EndianSwap::endian_swap(&mut self.{}, to_net);",
965 field_name,
966 )?;
967 }
968 "u16" | "u32" | "u64" | "i16" | "i32" | "i64" => match &field.size {
969 Some(FieldSize::Fixed(size)) => {
970 writeln!(self.output_file, " for i in 0..{} {{", size)?;
971 writeln!(
972 self.output_file,
973 " self.{}[i] = self.{}[i].to_be();",
974 field_name, field_name
975 )?;
976 writeln!(self.output_file, " }}",)?;
977 }
978 Some(FieldSize::Variable(Some(count_field))) => {
979 gen_count_variable(count_field)?;
980 writeln!(self.output_file, " for elem in array {{")?;
981 writeln!(self.output_file, " *elem = elem.to_be();",)?;
982 writeln!(self.output_file, " }}")?;
983 }
984 Some(FieldSize::Variable(None)) => {
985 return Err(Error::Unimplemented(format!(
986 "variable length array field {} without count",
987 field_name
988 )));
989 }
990 None => {
991 writeln!(
992 self.output_file,
993 " self.{} = self.{}.to_be();",
994 field_name, field.name
995 )?;
996 }
997 },
998 "f64" => {
999 writeln!(
1000 self.output_file,
1001 " // self.{} = self.{} (no-op according to VPP API)",
1002 field_name, field_name
1003 )?;
1004 }
1005 _ => match &field.size {
1006 Some(FieldSize::Fixed(size)) => {
1007 writeln!(self.output_file, " for i in 0..{} {{", size)?;
1008 writeln!(
1009 self.output_file,
1010 " ::vpp_plugin::vlibapi::EndianSwap::endian_swap(&mut self.{}[i], to_net);",
1011 field_name
1012 )?;
1013 writeln!(self.output_file, " }}",)?;
1014 }
1015 Some(FieldSize::Variable(Some(count_field))) => {
1016 gen_count_variable(count_field)?;
1017 writeln!(self.output_file, " for elem in array {{")?;
1018 writeln!(
1019 self.output_file,
1020 " ::vpp_plugin::vlibapi::EndianSwap::endian_swap(elem, to_net);",
1021 )?;
1022 writeln!(self.output_file, " }}",)?;
1023 }
1024 Some(FieldSize::Variable(None)) => {
1025 return Err(Error::Unimplemented(format!(
1026 "variable length array field {} without count",
1027 field_name
1028 )));
1029 }
1030 None => {
1031 writeln!(
1034 self.output_file,
1035 " ::vpp_plugin::vlibapi::EndianSwap::endian_swap(&mut self.{}, to_net);",
1036 field_name,
1037 )?;
1038 }
1039 },
1040 }
1041 }
1042 writeln!(self.output_file, " }}",)?;
1043 writeln!(self.output_file, " }}",)?;
1044 writeln!(self.output_file, "}}")?;
1045 writeln!(self.output_file)?;
1046
1047 Ok(())
1048 }
1049
1050 fn generate_type(&mut self, t: &Type) -> Result<(), Error> {
1051 let upper_camel_name = to_upper_camel_case(t.name());
1052
1053 let opt_derives = if t.manual_print() {
1054 ""
1055 } else if t.vla_non_recursive().is_some() {
1056 "Default, "
1057 } else {
1058 "Debug, PartialEq, Default, "
1059 };
1060 writeln!(self.output_file, "#[derive({}Copy, Clone)]", opt_derives)?;
1061 writeln!(self.output_file, "#[repr(C, packed)]")?;
1062 writeln!(self.output_file, "pub struct {} {{", upper_camel_name)?;
1063 for field in t.fields() {
1064 self.generate_field(field)?;
1065 }
1066 writeln!(self.output_file, "}}")?;
1067 writeln!(self.output_file)?;
1068
1069 if let Some((field, _)) = t.vla(self.parser)
1070 && let Some(FieldSize::Variable(Some(count_field))) = &field.size
1071 {
1072 writeln!(self.output_file, "impl {} {{", upper_camel_name)?;
1073 self.generate_vla_accessors(count_field, field)?;
1074 writeln!(self.output_file, "}}")?;
1075 writeln!(self.output_file)?;
1076 }
1077
1078 if t.vla_non_recursive().is_some() {
1081 self.generate_debug_trait(t.name(), t.fields())?;
1082 }
1083
1084 if !t.manual_endian() {
1085 self.generate_endian_swap(t.name(), EndianSwapInput::Fields(t.fields()))?;
1086 }
1087 Ok(())
1088 }
1089
1090 fn generate_types(&mut self) -> Result<(), Error> {
1091 for t in self.parser.types() {
1092 self.generate_type(t)?;
1093 }
1094 Ok(())
1095 }
1096
1097 fn generate_register(&mut self) -> Result<(), Error> {
1098 if self.parser.services().is_empty() {
1100 return Ok(());
1101 }
1102
1103 writeln!(self.output_file, "pub trait Handlers {{")?;
1104 for service in self.parser.services() {
1105 let caller_upper_camel = to_upper_camel_case(service.caller());
1106 let caller_message = self.parser.message(service.caller());
1107 let reply_message = if service.reply() == "null" {
1108 None
1109 } else {
1110 self.parser.message(service.reply())
1111 };
1112 let caller_message_vla = caller_message
1113 .map(|message| message.vla(self.parser).is_some())
1114 .unwrap_or(false);
1115 let reply_message_vla = reply_message
1116 .map(|message| message.vla(self.parser).is_some())
1117 .unwrap_or(false);
1118 let unsafe_str = if caller_message_vla || reply_message_vla {
1121 "unsafe "
1122 } else {
1123 ""
1124 };
1125 if service.reply() == "null" {
1126 writeln!(
1127 self.output_file,
1128 " {}fn {}(vm: &::vpp_plugin::vlib::BarrierHeldMainRef, mp: &{});",
1129 unsafe_str,
1130 service.caller(),
1131 caller_upper_camel
1132 )?;
1133 } else {
1134 let reply_message = format!(
1135 "::vpp_plugin::vlibapi::Message<{}>",
1136 to_upper_camel_case(service.reply())
1137 );
1138 let retval_in_reply_msg = self
1139 .parser
1140 .message(service.reply())
1141 .map(|reply| reply.has_retval())
1142 .unwrap_or_default();
1143 if let Some(stream_message) = service.stream_message() {
1144 let stream_message = format!(
1145 "::vpp_plugin::vlibapi::Stream<{}>",
1146 to_upper_camel_case(stream_message),
1147 );
1148 if retval_in_reply_msg {
1149 writeln!(
1150 self.output_file,
1151 " {}fn {}(vm: &::vpp_plugin::vlib::BarrierHeldMainRef, mp: &{}, stream: {}) -> Result<{}, i32>;",
1152 unsafe_str,
1153 service.caller(),
1154 caller_upper_camel,
1155 stream_message,
1156 reply_message
1157 )?;
1158 } else {
1159 writeln!(
1160 self.output_file,
1161 " {}fn {}(vm: &::vpp_plugin::vlib::BarrierHeldMainRef, mp: &{}, stream: {}) -> {};",
1162 unsafe_str,
1163 service.caller(),
1164 caller_upper_camel,
1165 stream_message,
1166 reply_message
1167 )?;
1168 }
1169 } else if service.stream() {
1170 writeln!(
1171 self.output_file,
1172 " {}fn {}(vm: &::vpp_plugin::vlib::BarrierHeldMainRef, mp: &{}, stream: ::vpp_plugin::vlibapi::Stream<{}>);",
1173 unsafe_str,
1174 service.caller(),
1175 caller_upper_camel,
1176 to_upper_camel_case(service.reply()),
1177 )?;
1178 } else if retval_in_reply_msg {
1179 writeln!(
1180 self.output_file,
1181 " {}fn {}(vm: &::vpp_plugin::vlib::BarrierHeldMainRef, mp: &{}) -> Result<{}, i32>;",
1182 unsafe_str,
1183 service.caller(),
1184 caller_upper_camel,
1185 reply_message
1186 )?;
1187 } else {
1188 writeln!(
1189 self.output_file,
1190 " {}fn {}(vm: &::vpp_plugin::vlib::BarrierHeldMainRef, mp: &{}) -> {};",
1191 unsafe_str,
1192 service.caller(),
1193 caller_upper_camel,
1194 reply_message
1195 )?;
1196 }
1197 }
1198 }
1199 writeln!(self.output_file, "}}")?;
1200 writeln!(self.output_file)?;
1201
1202 for service in self.parser.services() {
1203 let caller_upper_camel = to_upper_camel_case(service.caller());
1204 writeln!(
1205 self.output_file,
1206 "unsafe extern \"C\" fn {}_handler_raw<H: Handlers>(mp: *mut {}) {{",
1207 service.caller(),
1208 caller_upper_camel
1209 )?;
1210 writeln!(self.output_file, " unsafe {{")?;
1211 writeln!(
1212 self.output_file,
1213 " let vm = ::vpp_plugin::vlib::BarrierHeldMainRef::from_ptr_mut("
1214 )?;
1215 writeln!(
1216 self.output_file,
1217 " ::vpp_plugin::bindings::vlib_get_main_not_inline(),"
1218 )?;
1219 writeln!(self.output_file, " );")?;
1220 writeln!(self.output_file, " let mp = &*mp;")?;
1221 if service.reply() == "null" {
1222 writeln!(self.output_file, " H::{}(vm, mp);", service.caller())?;
1223 } else {
1224 writeln!(
1225 self.output_file,
1226 " ::vpp_plugin::vlibapi::registration_scope(|s| {{"
1227 )?;
1228 writeln!(
1231 self.output_file,
1232 " if let Some(reg) = s.from_client_index(vm, mp.client_index) {{"
1233 )?;
1234 let retval_in_reply_msg = self
1235 .parser
1236 .message(service.reply())
1237 .map(|reply| reply.has_retval())
1238 .unwrap_or_default();
1239 let stream_message_arg = if service.stream_message().is_some() {
1240 ", ::vpp_plugin::vlibapi::Stream::new(reg)"
1241 } else {
1242 ""
1243 };
1244 if service.stream() && service.stream_message().is_none() {
1245 writeln!(
1246 self.output_file,
1247 " H::{}(vm, mp, ::vpp_plugin::vlibapi::Stream::new(reg));",
1248 service.caller()
1249 )?;
1250 } else if retval_in_reply_msg {
1251 writeln!(
1252 self.output_file,
1253 " let mut reply = match H::{}(vm, mp{}) {{",
1254 service.caller(),
1255 stream_message_arg,
1256 )?;
1257 writeln!(self.output_file, " Ok(reply) => reply,")?;
1258 writeln!(
1259 self.output_file,
1260 " Err(retval) => {} {{",
1261 to_upper_camel_case(service.reply())
1262 )?;
1263 writeln!(self.output_file, " retval,")?;
1264 writeln!(
1265 self.output_file,
1266 " ..Default::default()"
1267 )?;
1268 writeln!(self.output_file, " }}")?;
1269 writeln!(self.output_file, " .into(),")?;
1270 writeln!(self.output_file, " }};")?;
1271 } else {
1272 writeln!(
1273 self.output_file,
1274 " let mut reply = H::{}(vm, mp{});",
1275 service.caller(),
1276 stream_message_arg,
1277 )?;
1278 }
1279 if !service.stream() || service.stream_message().is_some() {
1280 writeln!(
1281 self.output_file,
1282 " reply.context = mp.context;",
1283 )?;
1284 writeln!(
1285 self.output_file,
1286 " {}_endian(::std::ptr::addr_of_mut!(*reply), true);",
1287 service.reply()
1288 )?;
1289 writeln!(self.output_file, " reg.send_message(reply);")?;
1290 }
1291 writeln!(self.output_file, " }}")?;
1292 writeln!(self.output_file, " }})")?;
1293 writeln!(self.output_file, " }}")?;
1294 }
1295 writeln!(self.output_file, "}}")?;
1296 writeln!(self.output_file)?;
1297 }
1298
1299 writeln!(
1300 self.output_file,
1301 "pub const MESSAGE_COUNT: u16 = {};",
1302 self.parser.messages().len()
1303 )?;
1304 writeln!(self.output_file)?;
1305
1306 writeln!(
1307 self.output_file,
1308 "static MSG_ID_BASE: ::std::sync::atomic::AtomicU16 = ::std::sync::atomic::AtomicU16::new(0);"
1309 )?;
1310 writeln!(self.output_file)?;
1311 writeln!(self.output_file, "pub fn msg_id_base() -> u16 {{")?;
1312 writeln!(
1313 self.output_file,
1314 " MSG_ID_BASE.load(::std::sync::atomic::Ordering::Relaxed)"
1315 )?;
1316 writeln!(self.output_file, "}}")?;
1317 writeln!(self.output_file)?;
1318
1319 writeln!(
1320 self.output_file,
1321 "pub fn {}_register_messages<H: Handlers>() {{",
1322 self.module
1323 )?;
1324 writeln!(self.output_file, " unsafe {{")?;
1325 writeln!(
1326 self.output_file,
1327 " let am = ::vpp_plugin::bindings::vlibapi_helper_get_main();"
1328 )?;
1329 writeln!(
1330 self.output_file,
1331 " let mut json_api_repr = ::vpp_plugin::vppinfra::vec::Vec::from_raw((*am).json_api_repr);"
1332 )?;
1333 writeln!(self.output_file, " json_api_repr.push(",)?;
1334 writeln!(
1335 self.output_file,
1336 " concat!(include_str!(\"{}.api.json\"), \"\\0\")",
1337 self.module
1338 )?;
1339 writeln!(self.output_file, " .as_ptr()",)?;
1340 writeln!(self.output_file, " .cast_mut(),",)?;
1341 writeln!(self.output_file, " );",)?;
1342 writeln!(
1343 self.output_file,
1344 " (*am).json_api_repr = json_api_repr.into_raw();"
1345 )?;
1346 writeln!(self.output_file)?;
1347 writeln!(
1348 self.output_file,
1349 " let msg_id_base = ::vpp_plugin::bindings::vl_msg_api_get_msg_ids(",
1350 )?;
1351 writeln!(
1352 self.output_file,
1353 " c\"{}_{:08x}\".as_ptr() as *mut ::std::os::raw::c_char,",
1354 self.module,
1355 self.parser.file_crc()
1356 )?;
1357 writeln!(self.output_file, " MESSAGE_COUNT as i32,",)?;
1358 writeln!(self.output_file, " );",)?;
1359 writeln!(self.output_file)?;
1360 for message in self.parser.messages() {
1361 writeln!(
1362 self.output_file,
1363 " ::vpp_plugin::bindings::vl_msg_api_add_msg_name_crc("
1364 )?;
1365 writeln!(self.output_file, " am,")?;
1366 writeln!(
1367 self.output_file,
1368 " c\"{}_{:08x}\".as_ptr() as *mut ::std::os::raw::c_char,",
1369 message.name(),
1370 message.crc()
1371 )?;
1372 writeln!(
1373 self.output_file,
1374 " {}::MSG_ID as u32 + msg_id_base as u32,",
1375 to_upper_camel_case(message.name()),
1376 )?;
1377 writeln!(self.output_file, " );")?;
1378 writeln!(self.output_file)?;
1379 }
1380 for service in self.parser.services() {
1381 let caller = self.parser.message(service.caller()).unwrap();
1382 let caller_upper_camel = to_upper_camel_case(service.caller());
1383 writeln!(
1384 self.output_file,
1385 " let mut c = vpp_plugin::bindings::vl_msg_api_msg_config_t {{"
1386 )?;
1387 writeln!(
1388 self.output_file,
1389 " id: {}::MSG_ID as i32 + msg_id_base as i32,",
1390 caller_upper_camel,
1391 )?;
1392 writeln!(
1393 self.output_file,
1394 " name: c\"{}\".as_ptr() as *mut ::std::os::raw::c_char,",
1395 service.caller()
1396 )?;
1397 writeln!(
1398 self.output_file,
1399 " handler: {}_handler_raw::<H> as *mut ::std::os::raw::c_void,",
1400 service.caller()
1401 )?;
1402 writeln!(
1403 self.output_file,
1404 " endian: {}_endian as *mut ::std::os::raw::c_void,",
1405 service.caller()
1406 )?;
1407 writeln!(
1408 self.output_file,
1409 " format_fn: {}_format as *mut ::std::os::raw::c_void,",
1410 service.caller()
1411 )?;
1412 writeln!(
1413 self.output_file,
1414 " tojson: std::ptr::null_mut(),"
1415 )?;
1416 writeln!(
1417 self.output_file,
1418 " fromjson: std::ptr::null_mut(),"
1419 )?;
1420 writeln!(
1421 self.output_file,
1422 " calc_size: {}_calc_size as *mut ::std::os::raw::c_void,",
1423 service.caller()
1424 )?;
1425 writeln!(self.output_file, " ..Default::default()")?;
1426 writeln!(self.output_file, " }};")?;
1427 writeln!(self.output_file, " c.set_traced(1);")?;
1428 writeln!(self.output_file, " c.set_replay(1);")?;
1429 if caller.auto_endian() {
1431 writeln!(self.output_file, " c.set_is_autoendian(1);")?;
1432 }
1433 writeln!(
1434 self.output_file,
1435 " ::vpp_plugin::bindings::vl_msg_api_config(std::ptr::addr_of_mut!(c));"
1436 )?;
1437 writeln!(self.output_file)?;
1438
1439 if service.reply() != "null" {
1440 let reply = self.parser.message(service.reply()).unwrap();
1441 let reply_upper_camel = to_upper_camel_case(service.reply());
1442 writeln!(
1443 self.output_file,
1444 " let mut c = vpp_plugin::bindings::vl_msg_api_msg_config_t {{"
1445 )?;
1446 writeln!(
1447 self.output_file,
1448 " id: {}::MSG_ID as i32 + msg_id_base as i32,",
1449 reply_upper_camel
1450 )?;
1451 writeln!(
1452 self.output_file,
1453 " name: c\"{}\".as_ptr() as *mut ::std::os::raw::c_char,",
1454 service.reply()
1455 )?;
1456 writeln!(
1457 self.output_file,
1458 " handler: ::std::ptr::null_mut(),"
1459 )?;
1460 writeln!(
1461 self.output_file,
1462 " endian: {}_endian as *mut ::std::os::raw::c_void,",
1463 service.reply()
1464 )?;
1465 writeln!(
1466 self.output_file,
1467 " format_fn: {}_format as *mut ::std::os::raw::c_void,",
1468 service.reply()
1469 )?;
1470 writeln!(
1471 self.output_file,
1472 " tojson: std::ptr::null_mut(),"
1473 )?;
1474 writeln!(
1475 self.output_file,
1476 " fromjson: std::ptr::null_mut(),"
1477 )?;
1478 writeln!(
1479 self.output_file,
1480 " calc_size: {}_calc_size as *mut ::std::os::raw::c_void,",
1481 service.reply()
1482 )?;
1483 writeln!(self.output_file, " ..Default::default()")?;
1484 writeln!(self.output_file, " }};")?;
1485 writeln!(self.output_file, " c.set_traced(1);")?;
1486 writeln!(self.output_file, " c.set_replay(1);")?;
1487 if reply.auto_endian() {
1489 writeln!(self.output_file, " c.set_is_autoendian(1);")?;
1490 }
1491 writeln!(
1492 self.output_file,
1493 " ::vpp_plugin::bindings::vl_msg_api_config(std::ptr::addr_of_mut!(c));"
1494 )?;
1495 writeln!(self.output_file)?;
1496 }
1497
1498 if let Some(stream_message_name) = service.stream_message() {
1499 let stream_message = self.parser.message(stream_message_name).unwrap();
1500 let stream_message_upper_camel = to_upper_camel_case(stream_message_name);
1501 writeln!(
1502 self.output_file,
1503 " let mut c = vpp_plugin::bindings::vl_msg_api_msg_config_t {{"
1504 )?;
1505 writeln!(
1506 self.output_file,
1507 " id: {}::MSG_ID as i32 + msg_id_base as i32,",
1508 stream_message_upper_camel
1509 )?;
1510 writeln!(
1511 self.output_file,
1512 " name: c\"{}\".as_ptr() as *mut ::std::os::raw::c_char,",
1513 stream_message_name
1514 )?;
1515 writeln!(
1516 self.output_file,
1517 " handler: ::std::ptr::null_mut(),"
1518 )?;
1519 writeln!(
1520 self.output_file,
1521 " endian: {}_endian as *mut ::std::os::raw::c_void,",
1522 stream_message_name
1523 )?;
1524 writeln!(
1525 self.output_file,
1526 " format_fn: {}_format as *mut ::std::os::raw::c_void,",
1527 stream_message_name
1528 )?;
1529 writeln!(
1530 self.output_file,
1531 " tojson: std::ptr::null_mut(),"
1532 )?;
1533 writeln!(
1534 self.output_file,
1535 " fromjson: std::ptr::null_mut(),"
1536 )?;
1537 writeln!(
1538 self.output_file,
1539 " calc_size: {}_calc_size as *mut ::std::os::raw::c_void,",
1540 stream_message_name
1541 )?;
1542 writeln!(self.output_file, " ..Default::default()")?;
1543 writeln!(self.output_file, " }};")?;
1544 writeln!(self.output_file, " c.set_traced(1);")?;
1545 writeln!(self.output_file, " c.set_replay(1);")?;
1546 if stream_message.auto_endian() {
1548 writeln!(self.output_file, " c.set_is_autoendian(1);")?;
1549 }
1550 writeln!(
1551 self.output_file,
1552 " ::vpp_plugin::bindings::vl_msg_api_config(std::ptr::addr_of_mut!(c));"
1553 )?;
1554 writeln!(self.output_file)?;
1555 }
1556 }
1557
1558 writeln!(
1559 self.output_file,
1560 " MSG_ID_BASE.store(msg_id_base, ::std::sync::atomic::Ordering::Relaxed);"
1561 )?;
1562 writeln!(self.output_file, " }}")?;
1563 writeln!(self.output_file, "}}")?;
1564
1565 Ok(())
1566 }
1567
1568 fn generate(mut self) -> Result<(), Error> {
1569 self.output_json_file
1570 .write_all(generate_json(self.parser)?.as_bytes())?;
1571 self.generate_aliases()?;
1572 self.generate_enums()?;
1573 self.generate_unions()?;
1574 self.generate_types()?;
1575 self.generate_messages()?;
1576 self.generate_register()?;
1577 Ok(())
1578 }
1579}