use crate::error::ExtensionError;
#[allow(clippy::struct_excessive_bools)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ReleaseProfileCheck {
pub panic_abort: bool,
pub lto_enabled: bool,
pub opt_level_3: bool,
pub codegen_units_1: bool,
}
impl ReleaseProfileCheck {
#[must_use]
pub const fn is_required_satisfied(&self) -> bool {
self.panic_abort
}
#[must_use]
pub const fn is_fully_optimized(&self) -> bool {
self.panic_abort && self.lto_enabled && self.opt_level_3 && self.codegen_units_1
}
}
pub fn validate_release_profile(
panic: &str,
lto: &str,
opt_level: &str,
codegen_units: &str,
) -> Result<ReleaseProfileCheck, ExtensionError> {
let check = ReleaseProfileCheck {
panic_abort: panic == "abort",
lto_enabled: matches!(lto, "true" | "fat"),
opt_level_3: opt_level == "3",
codegen_units_1: codegen_units == "1",
};
if !check.panic_abort {
return Err(ExtensionError::new(
"release profile must set panic = \"abort\"; \
panics across FFI boundaries are undefined behavior in Rust",
));
}
Ok(check)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fully_optimized() {
let check = validate_release_profile("abort", "true", "3", "1").unwrap();
assert!(check.is_fully_optimized());
assert!(check.is_required_satisfied());
}
#[test]
fn fat_lto_accepted() {
let check = validate_release_profile("abort", "fat", "3", "1").unwrap();
assert!(check.lto_enabled);
}
#[test]
fn thin_lto_not_full() {
let check = validate_release_profile("abort", "thin", "3", "1").unwrap();
assert!(!check.lto_enabled);
assert!(!check.is_fully_optimized());
}
#[test]
fn no_lto_still_passes_required() {
let check = validate_release_profile("abort", "false", "2", "16").unwrap();
assert!(check.is_required_satisfied());
assert!(!check.is_fully_optimized());
}
#[test]
fn panic_unwind_rejected() {
let err = validate_release_profile("unwind", "true", "3", "1").unwrap_err();
assert!(err.as_str().contains("panic"));
assert!(err.as_str().contains("abort"));
}
#[test]
fn empty_panic_rejected() {
assert!(validate_release_profile("", "true", "3", "1").is_err());
}
#[test]
fn check_fields_independent() {
let check = validate_release_profile("abort", "false", "2", "4").unwrap();
assert!(check.panic_abort);
assert!(!check.lto_enabled);
assert!(!check.opt_level_3);
assert!(!check.codegen_units_1);
}
}