fbs_build/
compile.rs

1use crate::{
2    codegen::{CodeGenerator, RpcGenerator},
3    ir::Builder,
4};
5/// Compile flatbuffers files
6use std::io::{self, Write};
7use std::{
8    path::{Path, PathBuf},
9    process::{Command, Stdio},
10};
11
12use anyhow::{anyhow, Result};
13
14/// Generate Rust code for a single flatbuffer schema file from arbitrary input and to arbitrary
15/// output.
16pub fn compile_fbs_generic(
17    ugly: bool,
18    rpc_gen: Option<Box<dyn RpcGenerator>>,
19    mut input: Box<dyn io::Read>,
20    mut output: Box<dyn io::Write>,
21) -> Result<()> {
22    let mut schema_text = String::new();
23    input.read_to_string(&mut schema_text)?;
24
25    // parse the schema
26    let (rest, schema) =
27        crate::parser::schema_decl(schema_text.as_str()).map_err(|_| anyhow!("parse failed"))?;
28    if !rest.is_empty() {
29        return Err(anyhow!(
30            "Parse was incomplete: not parsed: {}...",
31            &rest[..30]
32        ));
33    }
34    let root = Builder::build(schema).map_err(|e| anyhow!("semantic analysis failed, {}", e))?;
35
36    let mut generator = CodeGenerator { root, rpc_gen };
37
38    let code = format!("{}", generator.build_token_stream());
39
40    let text_output = if !ugly {
41        let mut cmd = Command::new("rustfmt")
42            .stdin(Stdio::piped())
43            .stdout(Stdio::piped())
44            .arg("--edition")
45            .arg("2018")
46            .arg("--config")
47            .arg("normalize_doc_attributes=true")
48            .spawn()?;
49        cmd.stdin
50            .as_mut()
51            .ok_or_else(|| anyhow!("cannot access stdin"))?
52            .write_all(code.as_bytes())?;
53        cmd.wait_with_output()?.stdout
54    } else {
55        Vec::from(code)
56    };
57    output.write_all(&text_output[..])?;
58    Ok(())
59}
60
61/// Generate Rust code for a single flatbuffer schema file.
62pub fn compile_fbs(path: impl AsRef<Path>) -> Result<()> {
63    let out_dir = PathBuf::from(std::env::var("OUT_DIR")?);
64    let path_ref = path.as_ref();
65    let output_path = out_dir.join(
66        path_ref
67            .with_extension("rs")
68            .file_name()
69            .ok_or_else(|| anyhow!("path has no file_name: {:?}", path_ref))?,
70    );
71    let ugly = false;
72    compile_fbs_generic(
73        ugly,
74        None,
75        Box::new(std::fs::File::open(path_ref)?),
76        Box::new(std::fs::File::create(output_path)?),
77    )?;
78    Ok(())
79}