xtalforge_agent/
capabilities.rs1use std::collections::BTreeMap;
9
10use serde::{Deserialize, Serialize};
11use xtalforge_ff::{EngineKind, EngineStatus, probe};
12
13use crate::verbs;
14
15#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
17pub struct EngineAvailability {
18 pub name: String,
20 pub available: bool,
22 pub detail: String,
24}
25
26#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
28pub struct BundleAvailability {
29 pub name: String,
31 pub available: bool,
33 pub detail: String,
35}
36
37#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
39pub struct Capabilities {
40 pub version: String,
42 pub features: BTreeMap<String, bool>,
44 pub engines: Vec<EngineAvailability>,
46 pub bundles: Vec<BundleAvailability>,
48 pub verbs: Vec<String>,
50 pub formats: Vec<FormatAvailability>,
52}
53
54#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
56pub struct FormatAvailability {
57 pub name: String,
59 pub extensions: Vec<String>,
61 pub readable: bool,
63 pub writable: bool,
65}
66
67fn engine(kind: EngineKind) -> EngineAvailability {
68 let status = probe(kind);
69 match status {
70 EngineStatus::Available { path, version } => EngineAvailability {
71 name: kind.binary().to_owned(),
72 available: true,
73 detail: format!("{path} ({version})"),
74 },
75 EngineStatus::Missing { reason } => EngineAvailability {
76 name: kind.binary().to_owned(),
77 available: false,
78 detail: reason,
79 },
80 }
81}
82
83fn rcsr_bundle() -> BundleAvailability {
84 match xtalforge_analysis::RcsrIndex::from_embedded() {
85 Ok(index) => BundleAvailability {
86 name: "rcsr".to_owned(),
87 available: true,
88 detail: format!("{} RCSR nets, release 2019-06-01", index.len()),
89 },
90 Err(error) => BundleAvailability {
91 name: "rcsr".to_owned(),
92 available: false,
93 detail: error.to_string(),
94 },
95 }
96}
97
98#[must_use]
100pub fn capability_report() -> Capabilities {
101 let mut features = BTreeMap::new();
102 features.insert("parallel".to_owned(), cfg!(feature = "parallel"));
103 features.insert("sci-form".to_owned(), cfg!(feature = "sci-form"));
104 features.insert("ml".to_owned(), cfg!(feature = "ml"));
105 features.insert("external".to_owned(), cfg!(feature = "external"));
106 let formats = xtalforge_io::registry::FORMATS
107 .iter()
108 .map(|format| FormatAvailability {
109 name: format.name.to_owned(),
110 extensions: format
111 .extensions
112 .iter()
113 .map(|extension| (*extension).to_owned())
114 .collect(),
115 readable: format.read.is_some(),
116 writable: format.write.is_some(),
117 })
118 .collect();
119 Capabilities {
120 version: xtalforge_core::version().to_owned(),
121 features,
122 engines: vec![
123 engine(EngineKind::DftbPlus),
124 engine(EngineKind::Xtb),
125 engine(EngineKind::Orca),
126 ],
127 bundles: vec![rcsr_bundle()],
128 verbs: verbs::names()
129 .iter()
130 .map(|name| (*name).to_owned())
131 .collect(),
132 formats,
133 }
134}