use std::fmt;
use crate::Value;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct Facts {
pub bounds: Option<Bounds>,
pub init: Option<u64>,
pub align: Option<u32>,
pub live: bool,
}
impl Facts {
pub const NONE: Self = Self { bounds: None, init: None, align: None, live: false };
#[must_use]
pub const fn is_empty(self) -> bool {
self.bounds.is_none() && self.init.is_none() && self.align.is_none() && !self.live
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Bounds {
pub lo: Value,
pub ext: Value,
}
impl fmt::Display for Facts {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut first = true;
let mut sep = |f: &mut fmt::Formatter<'_>| {
let out = if first { Ok(()) } else { f.write_str(", ") };
first = false;
out
};
if let Some(bounds) = self.bounds {
sep(f)?;
write!(f, "!bounds(%{}, %{})", bounds.lo.raw(), bounds.ext.raw())?;
}
if self.live {
sep(f)?;
f.write_str("!live")?;
}
if let Some(n) = self.init {
sep(f)?;
write!(f, "!init({n})")?;
}
if let Some(align) = self.align {
sep(f)?;
write!(f, "!aligned({align})")?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn nothing_known_prints_as_nothing() {
assert!(Facts::NONE.is_empty());
assert_eq!(Facts::NONE.to_string(), "");
assert_eq!(Facts::default(), Facts::NONE);
}
#[test]
fn the_facts_print_in_the_order_the_specification_lists_them() {
let facts = Facts {
bounds: Some(Bounds { lo: Value::from_usize(3), ext: Value::from_usize(4) }),
init: Some(16),
align: Some(8),
live: true,
};
assert!(!facts.is_empty());
assert_eq!(facts.to_string(), "!bounds(%3, %4), !live, !init(16), !aligned(8)");
}
#[test]
fn one_fact_on_its_own_carries_no_separator() {
assert_eq!(Facts { live: true, ..Facts::NONE }.to_string(), "!live");
assert_eq!(Facts { align: Some(4), ..Facts::NONE }.to_string(), "!aligned(4)");
}
}