use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
pub const EXTRACTOR_VERSION: u32 = 1;
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct IndexStats {
#[serde(default)]
pub unresolved_references: usize,
#[serde(default)]
pub parse_failures: ParseFailures,
#[serde(default)]
pub syntax_error_files: Vec<String>,
#[serde(default)]
pub last_run_files: usize,
#[serde(default)]
pub skipped: SkippedFiles,
#[serde(default)]
pub dependencies: DependencyState,
#[serde(default)]
pub extractor_version: u32,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct ParseFailures {
pub count: usize,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub first: Option<ParseFailure>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct ParseFailure {
pub path: String,
pub error: String,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct SkippedFiles {
pub too_large: usize,
pub unreadable: usize,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "state", rename_all = "snake_case")]
pub enum DependencyState {
#[default]
NotApplicable,
Indexed { packages: usize },
Partial {
packages: usize,
missing: Vec<String>,
},
DiscoveryFailed { error: String },
}
impl DependencyState {
pub fn describe(&self) -> String {
match self {
DependencyState::NotApplicable => "not applicable (no Cargo.toml)".to_string(),
DependencyState::Indexed { packages } => format!("indexed ({packages} packages)"),
DependencyState::Partial { packages, missing } => {
let shown: Vec<&str> = missing.iter().take(5).map(String::as_str).collect();
let more = missing.len().saturating_sub(shown.len());
format!(
"partly indexed ({packages} packages; {} not downloaded: {}{}; run `cargo fetch`)",
missing.len(),
shown.join(", "),
if more > 0 {
format!(" and {more} more")
} else {
String::new()
}
)
}
DependencyState::DiscoveryFailed { error } => format!(
"not indexed (cargo metadata failed: {}; run `cargo fetch` or fix Cargo.toml)",
error.lines().next().unwrap_or("unknown error").trim()
),
}
}
pub fn is_problem(&self) -> bool {
matches!(
self,
DependencyState::Partial { .. } | DependencyState::DiscoveryFailed { .. }
)
}
}