1extern crate nom;
2
3use std::path::Path;
4use std::env;
5use std::fs;
6use std::io;
7use parser::Message;
8use std::path::PathBuf;
9
10pub mod generator;
11pub mod parser;
12
13pub fn process_current_dir() -> io::Result<()> {
14 process_dir(&env::current_dir()?)
15}
16
17fn convert_error<T>(r: Result<T, String>) -> Result<T, io::Error> {
18 r.map_err(|s| io::Error::new(io::ErrorKind::Other, s))
19}
20
21fn get_out_dir() -> io::Result<PathBuf> {
22 match env::var_os("OUT_DIR") {
23 Some(var) => Ok(PathBuf::from(&var)),
24 None => return convert_error(Err("missing OUT_DIR variable".to_string())),
25 }
26}
27
28pub fn process_dir(path: &Path) -> io::Result<()> {
29 let out_dir = get_out_dir()?;
30 let name = path.components().last().expect("not a valid path");
31 let out_file = out_dir.join(Path::new(&name)).with_extension("rs");
32
33 process_dir_to(path, &out_file, None)
34}
35
36pub fn process_dir_to(path: &Path, out_file: &Path, post_process: Option<&Fn(&str) -> String>) -> io::Result<()> {
37 fs::create_dir_all(out_file.parent().expect("No parent for out file"))?;
38 let messages = parse_dir_int(path)?;
39 process(messages, &out_file, post_process)?;
40
41 Ok(())
42}
43
44pub fn process_file(path: &Path, post_process: Option<&Fn(&str) -> String>) -> io::Result<()> {
45 let messages = parse_file(&path)?;
46
47 let out_dir = get_out_dir()?;
48 let name = path.components().last().expect("not a valid path");
49 let out_file = out_dir.join(Path::new(&name)).with_extension("rs");
50
51 process(messages, &out_file, post_process)
52}
53
54fn parse_dir_int(path: &Path) -> io::Result<Vec<Message>> {
55 println!("process dir {}", path.to_string_lossy());
56
57 let mut messages = vec![];
58
59 for entry in fs::read_dir(path)? {
60 let entry = entry?;
61
62 if entry.file_type()?.is_dir() {
63 messages.extend(parse_dir_int(&entry.path())?);
64 } else if entry.path().extension().iter().any(|ext| *ext == "protogen") {
65 messages.extend(parse_file(&entry.path())?);
66 }
67 };
68
69 Ok(messages)
70}
71
72fn parse_file(path: &Path) -> io::Result<Vec<Message>> {
73 let data = fs::read(path)?;
74
75 match parser::source_file(&data) {
76 Ok((rest, messages)) => {
77 let rest = String::from_utf8_lossy(&rest);
78
79 if rest.trim().is_empty() {
80 return Ok(messages);
81 } else {
82 return Err(io::Error::new(io::ErrorKind::Other,
83 format!("Parse error at {}", rest)));
84 }
85 }
86 Err(e) => {
87 return Err(io::Error::new(io::ErrorKind::Other,
88 format!("Parse error {:?}", e)));
89 }
90 }
91}
92
93fn process(messages: Vec<Message>, out_path: &Path, post_process: Option<&Fn(&str) -> String>) -> io::Result<()> {
94 let mut generated = convert_error(generator::Generator::from_messages(messages))?.to_string();
97 if let Some(process_fn) = post_process {
98 generated = process_fn(&generated);
99 }
100
101 fs::write(&out_path, generated)?;
102
103 Ok(())
104}