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
use crate::{
errors::{TebError, FAILED_TO_WRITE_TO_DST_FILE},
parser,
spec::STDOUT_DST,
DEFAULT_SPEC_PATH,
};
use log::error;
use std::{
fs::File,
io::{self, Write},
};
mod formatter;
mod generator;
mod options;
pub use options::*;
/// Generates code from a specification file.
///
/// See [CodegenOptions] for the information about function parameters.
///
/// # Examples
///
/// This example shows how the [codegen] function may be called directly.
/// However, the recommended and a shorter way to invoke the function
/// is using [CodegenOptions::codegen] method. See [CodegenOptions] for
/// a full example.
///
/// ```no_run
/// # use tighterror_build::{CodegenOptions, errors::TebError, codegen};
/// # pub fn foo() -> Result<(), TebError> {
/// let mut opts = CodegenOptions::new();
/// opts.spec("tighterror.yaml".to_owned());
/// codegen(&opts)?;
/// # Ok(())
/// # }
/// # foo().unwrap();
/// ```
pub fn codegen(opts: &CodegenOptions) -> Result<(), TebError> {
let path = opts.spec.as_deref().unwrap_or(DEFAULT_SPEC_PATH);
let spec = parser::from_path(path.into())?;
let code = generator::spec2code(&spec)?;
match spec.dst(opts.dst.as_deref()) {
p if p == STDOUT_DST => {
if let Err(e) = io::stdout().lock().write_all(code.as_bytes()) {
error!("failed to write to stdout: {e}");
return FAILED_TO_WRITE_TO_DST_FILE.into();
}
}
p => {
let mut file = match File::options()
.write(true)
.create(true)
.truncate(true)
.open(p)
{
Ok(f) => f,
Err(e) => {
error!("failed to open the destination file {:?}: {e}", p);
return FAILED_TO_WRITE_TO_DST_FILE.into();
}
};
if let Err(e) = file.write_all(code.as_bytes()) {
error!("failed to write to the destination file {:?}: {e}", p);
return FAILED_TO_WRITE_TO_DST_FILE.into();
}
file.flush().ok();
drop(file);
formatter::rustfmt(p).ok();
}
}
Ok(())
}