1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
//! To generate Rust types from an XDR spec at build time, add `fastxdr` to your //! `Cargo.toml`: //! //! ```toml //! [build-dependencies] //! # For the code generation //! fastxdr = "1.0" //! //! [dependencies] //! # Required dependencies of the generated code //! thiserror = "1.0" //! bytes = "0.5" //! ``` //! //! And add a `build.rs` at the crate root (not in `src`!): //! //! ```no_run //! # std::env::set_var("OUT_DIR", "./"); //! fn main() { //! // Tell Cargo to regenerate the types if the XDR spec changes //! println!("cargo:rerun-if-changed=xdr_spec.x"); //! //! // Read from xdr_spec.x, writing the generated code to out.rs //! std::fs::write( //! std::path::Path::new(std::env::var("OUT_DIR").unwrap().as_str()).join("out.rs"), //! fastxdr::Generator::default() //! .generate(include_str!("xdr_spec.x")) //! .unwrap(), //! ) //! .unwrap(); //! } //! ``` //! //! And then include the generated file in your application: //! //! ```compile_fail //! // Where out.rs is the filename from above //! include!(concat!(env!("OUT_DIR"), "/out.rs")); //! use xdr::*; //! ``` //! //! To view the generated types, either export the generated types in your //! application and use `cargo doc`, or use the CLI to produce the generated //! code directly for reading. #![allow(clippy::needless_doctest_main)] pub mod ast; pub mod impls; use crate::impls::{print_impl_from, print_impl_wire_size, print_types, template}; use std::fmt::Write; /// `DEFAULT_DERIVE` defines the default "derive" line prepended to type /// declarations. /// /// Custom "derive" lines can be used when generating Rust types with /// [`Generator::with_derive()`](Generator::with_derive). pub const DEFAULT_DERIVE: &str = "#[derive(Debug, PartialEq)]"; pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + 'static>>; #[derive(Debug)] pub struct Generator { derive: String, } impl std::default::Default for Generator { fn default() -> Self { Generator { derive: DEFAULT_DERIVE.to_string(), } } } impl Generator { pub fn with_derive<D: AsRef<str>>(self, derive: D) -> Self { Self { derive: derive.as_ref().to_string(), } } pub fn generate<T: AsRef<str>>(&self, xdr: T) -> Result<String> { // Create the AST let ast = crate::ast::Ast::new(xdr.as_ref())?; let mut out = String::new(); // Print the file header writeln!(out, "{}", include_str!("header.rs"))?; // Generate the types print_types(&mut out, &ast, &self.derive.as_str())?; // Write the two from traits, one for Bytes and one for &mut Bytes print_impl_from(&mut out, template::bytes::Bytes, &ast)?; print_impl_from(&mut out, template::bytes::RefMutBytes, &ast)?; // Write the wire_size() implementations print_impl_wire_size(&mut out, template::bytes::Bytes, &ast)?; // End the header.rs with a closing } writeln!(out, "}}")?; Ok(out) } }