use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
use crate::classify::TraceTier;
#[derive(
Debug, Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize,
)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum Stratum {
Exact,
RegexHigh,
RegexMid,
RegexOther,
WeightedSum,
Fuzzy,
CatchAll,
#[default]
Unknown,
Other,
}
impl Stratum {
pub const ALL: [Stratum; 9] = [
Stratum::Exact,
Stratum::RegexHigh,
Stratum::RegexMid,
Stratum::RegexOther,
Stratum::WeightedSum,
Stratum::Fuzzy,
Stratum::CatchAll,
Stratum::Unknown,
Stratum::Other,
];
pub fn as_str(self) -> &'static str {
match self {
Self::Exact => "exact",
Self::RegexHigh => "regex_high",
Self::RegexMid => "regex_mid",
Self::RegexOther => "regex_other",
Self::WeightedSum => "weighted_sum",
Self::Fuzzy => "fuzzy",
Self::CatchAll => "catch_all",
Self::Unknown => "unknown",
Self::Other => "other",
}
}
pub fn classify(tier: TraceTier, category: &str, confidence: f64) -> Self {
if tier == TraceTier::CatchAll {
return Self::CatchAll;
}
if tier == TraceTier::Unclassified
|| category.eq_ignore_ascii_case("uncategorized")
|| category.eq_ignore_ascii_case("unknown")
{
return Self::Unknown;
}
match tier {
TraceTier::Exact => Self::Exact,
TraceTier::Regex if confidence >= 0.9 => Self::RegexHigh,
TraceTier::Regex if (0.55..=0.7).contains(&confidence) => Self::RegexMid,
TraceTier::Regex => Self::RegexOther,
TraceTier::WeightedSum => Self::WeightedSum,
TraceTier::Fuzzy => Self::Fuzzy,
_ => Self::Other,
}
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Diffstat {
pub files: i64,
pub insertions: i64,
pub deletions: i64,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct SampleRecord {
pub sha: String,
pub repo: String,
pub date: String,
pub author_hash: String,
pub subject: String,
pub body: String,
pub paths: Vec<String>,
pub diffstat: Diffstat,
pub pr_title: Option<String>,
pub ticket_id: Option<String>,
pub issue_type: Option<String>,
pub stratum: Stratum,
pub method: String,
pub rule_id: String,
pub predicted_category: String,
pub confidence: f64,
pub weight: f64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub is_merge: Option<bool>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct StratumCounts {
pub population: u64,
pub sampled: u64,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct StrataSummary {
pub seed: u64,
pub weeks: u32,
pub window_start: String,
pub window_end: String,
pub requested_size: u64,
pub cap: u64,
pub population: u64,
#[serde(default)]
pub merges_excluded: u64,
pub strata: BTreeMap<String, StratumCounts>,
pub categories: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub subsample: Option<SubsampleOrigin>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct SubsampleOrigin {
pub seed: u64,
pub size: u64,
pub source_size: u64,
}
impl StrataSummary {
pub fn population_of(&self, stratum: Stratum) -> u64 {
self.strata
.get(stratum.as_str())
.map(|c| c.population)
.unwrap_or(0)
}
}