Functional Weave
Code in Rust

monitor.status-page@1.0.0

impl/rust.rs

2,282 bytes · the Rust implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one

// Worst last. Maintenance ranks below every real problem: an outage elsewhere
// during planned work is still the headline.
const RANK: [&str; 5] = ["operational", "maintenance", "degraded", "partial-outage", "major-outage"];
const HEADLINE: [&str; 5] = [
    "All systems operational",
    "Scheduled maintenance",
    "Degraded performance",
    "Partial outage",
    "Major outage",
];

/// The banner for a whole status page: the worst component state wins.
///
/// # Panics
/// Panics on no components, an empty or duplicate name, or an unknown state.
pub fn status_page(components: &[Component]) -> StatusSummary {
    if components.is_empty() {
        panic!("components must not be empty");
    }
    let mut seen: Vec<&str> = Vec::new();
    let mut worst = 0usize;
    let mut affected: Vec<String> = Vec::new();
    for c in components {
        if c.name.is_empty() {
            panic!("component name must not be empty");
        }
        if seen.contains(&c.name.as_str()) {
            panic!("duplicate component name: {}", c.name);
        }
        seen.push(&c.name);
        let rank = match RANK.iter().position(|r| *r == c.state) {
            Some(r) => r,
            None => panic!("unknown component state: {}", c.state),
        };
        if rank > worst {
            worst = rank;
        }
        if rank > 0 {
            affected.push(c.name.clone());
        }
    }
    StatusSummary {
        state: RANK[worst].to_string(),
        headline: HEADLINE[worst].to_string(),
        affected,
    }
}

/// A `Component` from its JSON form, for adapters of capabilities built on this one.
pub fn component_from_value(v: &Value) -> Component {
    Component { name: v.get("name").as_str().to_string(), state: v.get("state").as_str().to_string() }
}

pub fn status_summary_to_value(s: &StatusSummary) -> Value {
    Value::obj(vec![
        ("state", Value::str(&s.state)),
        ("headline", Value::str(&s.headline)),
        ("affected", Value::Arr(s.affected.iter().map(|a| Value::str(a)).collect())),
    ])
}

pub fn fune_vector(args: &[Value]) -> Value {
    let components: Vec<Component> = args[0].as_arr().iter().map(component_from_value).collect();
    status_summary_to_value(&status_page(&components))
}