kcode-rust-libs 0.2.3

Manage, validate, document, and publish small agent-authored Rust crates
Documentation
use std::fmt;

use crate::RustLibPath;

/// A complete text file in a managed Rust library.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RustLibFile {
    pub path: RustLibPath,
    pub contents: String,
}

impl RustLibFile {
    pub fn new(path: RustLibPath, contents: impl Into<String>) -> Self {
        Self {
            path,
            contents: contents.into(),
        }
    }
}

/// The agent-facing metadata stored in a managed Rust library.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RustLibDocs {
    /// The canonical `major.minor.patch` version without a trailing newline.
    pub version: String,
    /// The complete text of `Documentation.md`.
    pub documentation: String,
}

/// A stage in the standardized Rust validation pipeline.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CheckStage {
    Fetch,
    Format,
    Build,
    Clippy,
    Test,
    DocTest,
}

impl CheckStage {
    pub fn as_str(self) -> &'static str {
        match self {
            Self::Fetch => "fetch",
            Self::Format => "format",
            Self::Build => "build",
            Self::Clippy => "clippy",
            Self::Test => "test",
            Self::DocTest => "doc-test",
        }
    }
}

impl fmt::Display for CheckStage {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.as_str())
    }
}

/// Captured output from one validation stage.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CheckStageResult {
    pub stage: CheckStage,
    pub success: bool,
    pub exit_code: Option<i32>,
    pub stdout: String,
    pub stderr: String,
}

/// The outcome of a complete (or fail-fast) Rust library validation run.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CheckResult {
    pub stages: Vec<CheckStageResult>,
}

impl CheckResult {
    /// True only when every pipeline stage ran and passed.
    pub fn passed(&self) -> bool {
        self.stages.len() == 6 && self.stages.iter().all(|stage| stage.success)
    }

    /// Return the first unsuccessful stage, if one ran.
    pub fn failure(&self) -> Option<&CheckStageResult> {
        self.stages.iter().find(|stage| !stage.success)
    }
}