1use crate::{
2 codegen::{CodeGenerator, RpcGenerator},
3 ir::Builder,
4};
5use std::io::{self, Write};
7use std::{
8 path::{Path, PathBuf},
9 process::{Command, Stdio},
10};
11
12use anyhow::{anyhow, Result};
13
14pub 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 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
61pub 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}