#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Tier {
Bronze,
Silver,
Gold,
Platinum,
}
impl Tier {
#[must_use]
pub const fn strength(&self) -> u8 {
match self {
Self::Bronze => 0,
Self::Silver => 1,
Self::Gold => 2,
Self::Platinum => 3,
}
}
#[must_use]
pub const fn label(&self) -> &'static str {
match self {
Self::Bronze => "bronze",
Self::Silver => "silver",
Self::Gold => "gold",
Self::Platinum => "platinum",
}
}
#[must_use]
pub const fn is_stdlib_eligible_at_52(&self) -> bool {
!matches!(self, Self::Bronze)
}
#[must_use]
pub const fn requires_kani(&self) -> bool {
matches!(self, Self::Gold | Self::Platinum)
}
#[must_use]
pub const fn requires_lean_refinement(&self) -> bool {
matches!(self, Self::Platinum)
}
}
impl Default for Tier {
fn default() -> Self {
Self::Bronze
}
}
#[derive(Debug, Clone, Default)]
pub struct TierInputs<'a> {
pub decorators: Vec<&'a str>,
pub has_requires: bool,
pub has_ensures: bool,
pub has_yaml_contract: bool,
pub has_lean_proof: bool,
}
#[must_use]
pub fn classify(inputs: &TierInputs<'_>) -> Tier {
let has_bronze = inputs.decorators.iter().any(|d| *d == "bronze");
let has_gold = inputs.decorators.iter().any(|d| *d == "gold");
let has_platinum = inputs.decorators.iter().any(|d| *d == "platinum");
let has_contracts = inputs.has_requires || inputs.has_ensures;
if has_platinum && has_contracts && inputs.has_yaml_contract && inputs.has_lean_proof {
return Tier::Platinum;
}
if has_gold && has_contracts {
return Tier::Gold;
}
if has_bronze {
return Tier::Bronze;
}
if has_contracts {
return Tier::Silver;
}
Tier::Bronze
}
#[cfg(test)]
mod tests {
use super::*;
fn inputs(decorators: Vec<&'static str>, req: bool, ens: bool) -> TierInputs<'static> {
TierInputs {
decorators,
has_requires: req,
has_ensures: ens,
has_yaml_contract: false,
has_lean_proof: false,
}
}
#[test]
fn test_tier_order() {
assert!(Tier::Bronze.strength() < Tier::Silver.strength());
assert!(Tier::Silver.strength() < Tier::Gold.strength());
assert!(Tier::Gold.strength() < Tier::Platinum.strength());
}
#[test]
fn test_tier_labels() {
assert_eq!(Tier::Bronze.label(), "bronze");
assert_eq!(Tier::Silver.label(), "silver");
assert_eq!(Tier::Gold.label(), "gold");
assert_eq!(Tier::Platinum.label(), "platinum");
}
#[test]
fn test_stdlib_eligibility_at_52() {
assert!(!Tier::Bronze.is_stdlib_eligible_at_52());
assert!(Tier::Silver.is_stdlib_eligible_at_52());
assert!(Tier::Gold.is_stdlib_eligible_at_52());
assert!(Tier::Platinum.is_stdlib_eligible_at_52());
}
#[test]
fn test_kani_requirement() {
assert!(!Tier::Bronze.requires_kani());
assert!(!Tier::Silver.requires_kani());
assert!(Tier::Gold.requires_kani());
assert!(Tier::Platinum.requires_kani());
}
#[test]
fn test_lean_refinement_only_for_platinum() {
assert!(!Tier::Bronze.requires_lean_refinement());
assert!(!Tier::Silver.requires_lean_refinement());
assert!(!Tier::Gold.requires_lean_refinement());
assert!(Tier::Platinum.requires_lean_refinement());
}
#[test]
fn test_classify_bare_function_is_bronze() {
assert_eq!(classify(&inputs(vec![], false, false)), Tier::Bronze);
}
#[test]
fn test_classify_requires_only_is_silver() {
assert_eq!(classify(&inputs(vec![], true, false)), Tier::Silver);
}
#[test]
fn test_classify_ensures_only_is_silver() {
assert_eq!(classify(&inputs(vec![], false, true)), Tier::Silver);
}
#[test]
fn test_classify_both_clauses_is_silver() {
assert_eq!(classify(&inputs(vec![], true, true)), Tier::Silver);
}
#[test]
fn test_classify_gold_decorator_plus_contract_is_gold() {
assert_eq!(classify(&inputs(vec!["gold"], true, true)), Tier::Gold);
}
#[test]
fn test_classify_gold_decorator_without_contract_is_bronze() {
assert_eq!(classify(&inputs(vec!["gold"], false, false)), Tier::Bronze);
}
#[test]
fn test_classify_platinum_requires_full_stack() {
let partial = TierInputs {
decorators: vec!["platinum"],
has_requires: true,
has_ensures: true,
has_yaml_contract: false, has_lean_proof: false,
};
assert_eq!(classify(&partial), Tier::Silver);
let full = TierInputs {
decorators: vec!["platinum"],
has_requires: true,
has_ensures: true,
has_yaml_contract: true,
has_lean_proof: true,
};
assert_eq!(classify(&full), Tier::Platinum);
}
#[test]
fn test_classify_bronze_decorator_wins_over_contracts() {
assert_eq!(classify(&inputs(vec!["bronze"], true, true)), Tier::Bronze);
}
#[test]
fn test_classify_ignores_unrelated_decorators() {
assert_eq!(
classify(&inputs(vec!["verified", "total"], true, false)),
Tier::Silver
);
}
#[test]
fn test_default_tier_is_bronze() {
assert_eq!(Tier::default(), Tier::Bronze);
}
}