use std::collections::{BTreeMap, BTreeSet};
use std::path::{Path, PathBuf};
use super::code::{manifest_names, workspace_membership};
use super::gguf::ExtractError;
use crate::ontology::rdf::{iri_path, ont, Graph, Term, PROV_ENTITY, RDF_TYPE};
#[must_use]
pub fn ex(name: &str) -> String {
ont(&format!("example/{name}"))
}
pub const FAMILIES: &[(&str, &[&str])] = &[
("qwen3.5", &["qwen3.5", "qwen3_5", "qwen3-5", "qwen35"]),
("qwen3", &["qwen3"]),
("qwen2.5", &["qwen2.5", "qwen2_5", "qwen2-5", "qwen25"]),
("qwen2", &["qwen2"]),
("tinyllama", &["tinyllama"]),
("llama", &["llama"]),
("mistral", &["mistral"]),
("phi", &["phi-", "phi_", "phi2", "phi3", "phi4"]),
("gemma", &["gemma"]),
("smollm", &["smollm"]),
("gpt2", &["gpt2", "gpt-2"]),
("deepseek", &["deepseek"]),
];
pub const CURRENT_FAMILY: &str = "qwen3.5";
pub const STALE_EXAMPLES_PINNED: usize = 430;
pub const PIN_MARKER: &str = "ont:model-pinned:";
#[must_use]
pub fn pin_reason(text: &str) -> Option<String> {
text.lines()
.filter_map(|l| l.trim_start().strip_prefix("//"))
.filter_map(|l| {
l.trim_start_matches(['/', '!'])
.trim()
.strip_prefix(PIN_MARKER)
})
.map(str::trim)
.find(|r| !r.is_empty())
.map(str::to_string)
}
const NOT_A_MODEL: &[&str] = &["llama.cpp", "llama_cpp", "llama-cpp", "llamacpp"];
#[must_use]
pub fn families_in(text: &str) -> BTreeSet<&'static str> {
let lower = text.to_lowercase();
lower
.split(|c: char| !(c.is_ascii_alphanumeric() || matches!(c, '.' | '_' | '-')))
.filter(|t| !NOT_A_MODEL.iter().any(|n| t.starts_with(n)))
.filter_map(|t| {
if t == "phi" {
return Some("phi");
}
FAMILIES
.iter()
.find(|(_, prefixes)| prefixes.iter().any(|p| t.starts_with(p)))
.map(|(f, _)| *f)
})
.collect()
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Example {
pub file: String,
pub krate: String,
pub name: String,
pub families: BTreeSet<&'static str>,
pub pinned: Option<String>,
}
impl Example {
#[must_use]
pub fn model_current(&self) -> bool {
self.families.is_empty() || self.families.contains(CURRENT_FAMILY) || self.pinned.is_some()
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct ExampleStats {
pub at_workspace_root: bool,
pub members: usize,
pub packages: usize,
pub examples: usize,
pub non_member_examples: usize,
pub naming_a_model: usize,
pub naming_qwen35: usize,
pub stale: usize,
pub pinned: usize,
pub by_family: BTreeMap<String, usize>,
pub errors: Vec<ExtractError>,
}
#[must_use]
pub fn targets_of(dir: &Path) -> Vec<PathBuf> {
let Ok(rd) = std::fs::read_dir(dir.join("examples")) else {
return Vec::new();
};
let mut out: Vec<PathBuf> = rd
.flatten()
.map(|e| e.path())
.filter_map(|p| {
if p.is_dir() {
Some(p.join("main.rs")).filter(|m| m.is_file())
} else {
Some(p).filter(|p| p.extension().is_some_and(|e| e == "rs"))
}
})
.collect();
out.sort();
out
}
pub(crate) fn manifests(root: &Path) -> Vec<PathBuf> {
let mut out = Vec::new();
let mut stack = vec![root.to_path_buf()];
while let Some(dir) = stack.pop() {
let Ok(rd) = std::fs::read_dir(&dir) else {
continue;
};
for p in rd.flatten().map(|e| e.path()) {
let name = p.file_name().and_then(|n| n.to_str()).unwrap_or_default();
if p.is_dir() {
if !matches!(name, "target" | ".git" | ".lake" | "node_modules") {
stack.push(p);
}
} else if name == "Cargo.toml" {
out.push(p);
}
}
}
out.sort();
out
}
fn rel(root: &Path, p: &Path) -> String {
p.strip_prefix(root)
.unwrap_or(p)
.to_string_lossy()
.replace('\\', "/")
}
fn target_name(file: &Path) -> String {
let stem = file.file_stem().unwrap_or_default();
let name = if stem == "main" {
file.parent().and_then(Path::file_name).unwrap_or(stem)
} else {
stem
};
name.to_string_lossy().to_string()
}
#[must_use]
pub fn walk(root: &Path) -> (Vec<Example>, ExampleStats) {
let membership = std::fs::read_to_string(root.join("Cargo.toml"))
.ok()
.and_then(|t| workspace_membership(&t));
let mut stats = ExampleStats {
at_workspace_root: membership.is_some(),
..ExampleStats::default()
};
let mut out = Vec::new();
for manifest in manifests(root) {
let dir = manifest.parent().unwrap_or(root);
let package = std::fs::read_to_string(&manifest)
.ok()
.and_then(|t| manifest_names(&t).package);
let admitted = membership.as_ref().is_none_or(|m| m.admits(root, dir));
stats.members += usize::from(admitted && package.is_some());
let targets = targets_of(dir);
if targets.is_empty() {
continue;
}
let Some(krate) = package.filter(|_| admitted) else {
stats.non_member_examples += targets.len();
continue;
};
stats.packages += 1;
for file in targets {
let Ok(text) = std::fs::read_to_string(&file) else {
stats.errors.push(ExtractError {
file: rel(root, &file),
what: "example target is not readable UTF-8".into(),
});
continue;
};
out.push(Example {
file: rel(root, &file),
krate: krate.clone(),
name: target_name(&file),
families: families_in(&text),
pinned: pin_reason(&text),
});
}
}
stats.examples = out.len();
for e in &out {
stats.naming_a_model += usize::from(!e.families.is_empty());
stats.naming_qwen35 += usize::from(e.families.contains(CURRENT_FAMILY));
stats.stale += usize::from(!e.model_current());
stats.pinned += usize::from(e.pinned.is_some());
for f in &e.families {
*stats.by_family.entry((*f).to_string()).or_default() += 1;
}
}
if stats.at_workspace_root
&& stats.examples == 0
&& (stats.members == 0 || stats.non_member_examples > 0)
{
stats.errors.push(ExtractError {
file: "Cargo.toml".into(),
what: format!(
"a [workspace] root read zero example targets from {} member(s) while {} target(s) sat outside \
the membership — the walk measured nothing",
stats.members, stats.non_member_examples
),
});
}
(out, stats)
}
pub fn emit(g: &mut Graph, e: &Example) {
let n = iri_path("example", &e.file.split('/').collect::<Vec<_>>());
g.insert(n.clone(), RDF_TYPE, Term::iri(ont("Example")));
g.insert(n.clone(), RDF_TYPE, Term::iri(PROV_ENTITY));
g.insert(n.clone(), ex("file"), Term::string(&e.file));
g.insert(n.clone(), ex("crate"), Term::string(&e.krate));
g.insert(n.clone(), ex("name"), Term::string(&e.name));
for f in &e.families {
g.insert(n.clone(), ex("namesModel"), Term::string(*f));
}
g.insert(
n.clone(),
ex("namesQwen35"),
Term::boolean(e.families.contains(CURRENT_FAMILY)),
);
g.insert(
n.clone(),
ex("modelCurrent"),
Term::boolean(e.model_current()),
);
if let Some(r) = &e.pinned {
g.insert(n.clone(), ex("modelPinned"), Term::string(r));
}
}
pub fn extract(contract_dir: &Path, g: &mut Graph) -> ExampleStats {
let root = super::repo_root(contract_dir);
let (examples, stats) = walk(&root);
for e in &examples {
emit(g, e);
}
stats
}
#[must_use]
pub fn positive_control() -> bool {
let named = families_in("load Qwen3.5-4B, compare to phi-3 on graphics via llama.cpp");
let expected: BTreeSet<&str> = ["qwen3.5", "phi"].into_iter().collect();
let old = Example {
file: String::new(),
krate: String::new(),
name: String::new(),
families: families_in("Qwen2.5-Coder"),
pinned: pin_reason("// qwen2.5 on purpose"),
};
named == expected
&& families_in("Qwen3-8B").contains("qwen3")
&& !families_in("Qwen3-8B").contains("qwen3.5")
&& !old.model_current()
}
#[cfg(test)]
#[path = "example_tests.rs"]
mod tests;