use crate::core::ir::ErrorDef;
use super::shared::{duration_methods, error_variant_wildcard_pattern, millis_expr, to_snake_case};
fn core_error_path(error: &ErrorDef, core_import: &str) -> String {
if error.rust_path.is_empty() {
format!("{core_import}::{}", error.name)
} else {
error.rust_path.replace('-', "_")
}
}
pub fn rustler_typed_errors(errors: &[ErrorDef]) -> Vec<&ErrorDef> {
let mut typed: Vec<&ErrorDef> = errors.iter().filter(|error| !error.binding_excluded).collect();
typed.sort_by(|a, b| a.name.cmp(&b.name));
typed
}
pub fn rustler_error_module_name(error: &ErrorDef, app_module: &str, errors: &[&ErrorDef]) -> String {
let short = match error.name.strip_prefix(app_module) {
Some(rest) if !rest.is_empty() => rest.to_string(),
_ => error.name.clone(),
};
let taken =
errors
.iter()
.filter(|other| other.name != error.name)
.any(|other| match other.name.strip_prefix(app_module) {
Some(rest) if !rest.is_empty() => rest == short,
_ => other.name == short,
});
if taken { error.name.clone() } else { short }
}
pub fn rustler_converter_fn_name(error: &ErrorDef) -> String {
format!("{}_to_nif_err", to_snake_case(&error.name))
}
pub fn gen_rustler_error_converter(error: &ErrorDef, core_import: &str, exception_module: &str) -> String {
let rust_path = core_error_path(error, core_import);
let fn_name = rustler_converter_fn_name(error);
let arms = error
.variants
.iter()
.map(|variant| {
(
error_variant_wildcard_pattern(&rust_path, variant),
to_snake_case(&variant.name),
)
})
.collect::<Vec<_>>();
let status = if error.methods.iter().any(|m| m.name == "status_code") {
"e.status_code()"
} else {
"0"
};
let retry = match duration_methods(error)
.into_iter()
.find(|(m, _)| m.name == "retry_after")
{
Some((_, true)) => millis_expr("e.retry_after()", true, "u64"),
Some((_, false)) => format!("Some({})", millis_expr("e.retry_after()", false, "u64")),
None => "None".to_string(),
};
crate::codegen::template_env::render(
"error_gen/rustler_error_converter.jinja",
crate::alef_context! {
rust_path => rust_path, fn_name => fn_name, arms => arms,
exception_module => exception_module, status => status, retry => retry,
},
)
}
pub fn gen_rustler_error_support(errors: &[&ErrorDef], core_import: &str) -> String {
let arms = errors
.iter()
.map(|error| (core_error_path(error, core_import), rustler_converter_fn_name(error)))
.collect::<Vec<_>>();
crate::codegen::template_env::render(
"error_gen/rustler_error_support.jinja",
crate::alef_context! { arms => arms },
)
}