use crate::core::action::ToolchainInfo;
use miette::Diagnostic;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
pub const JSON_DIAGNOSTICS_ARG: &str = "--error-format=json";
#[derive(Debug, Clone, thiserror::Error, Diagnostic)]
pub enum RustAdapterError {
#[error("Manifest not found at {0}")]
#[diagnostic(
code(mitts::rust::manifest_not_found),
help(
"Ensure Cargo.toml exists at the specified path or run from a valid project directory."
)
)]
ManifestNotFound(PathBuf),
#[error("Unsupported build option: {0}")]
#[diagnostic(
code(mitts::rust::unsupported_option),
help("Run 'mitts build --help' to see supported options.")
)]
UnsupportedOption(String),
#[error("Cargo execution failed with exit code {0}")]
#[diagnostic(
code(mitts::rust::cargo_failed),
help("Check the compiler diagnostic output above for details.")
)]
CargoFailed(i32),
#[error("Metadata or compiler query failed: {0}")]
#[diagnostic(
code(mitts::rust::metadata_failed),
help(
"Ensure the Rust toolchain is installed and reachable. If the message names a dependency, \
check that Cargo.toml and Cargo.lock agree."
)
)]
MetadataFailed(String),
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct PlannedCompilationUnit {
#[serde(default)]
pub package_id: String,
pub package_name: String,
pub version: String,
pub target_name: String,
pub kind: String,
pub src_path: PathBuf,
#[serde(default)]
pub manifest_path: PathBuf,
pub cache_eligibility: String,
#[serde(default)]
pub is_workspace: bool,
#[serde(default)]
pub is_primary: bool,
#[serde(default)]
pub env_vars: Vec<String>,
#[serde(default)]
pub dependencies: Vec<String>,
#[serde(default)]
pub edition: Option<String>,
#[serde(default)]
pub features: Vec<String>,
#[serde(default)]
pub for_host: bool,
#[serde(default)]
pub workspace_root: Option<PathBuf>,
}
impl PlannedCompilationUnit {
pub fn unit_id(&self) -> String {
if self.for_host {
format!(
"{}::{}:{}:host",
self.package_id, self.kind, self.target_name
)
} else {
format!("{}::{}:{}", self.package_id, self.kind, self.target_name)
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EffectivePlanExplanation {
pub manifest_path: PathBuf,
pub target_directory: PathBuf,
pub profile: String,
pub toolchain: ToolchainInfo,
pub units: Vec<PlannedCompilationUnit>,
#[serde(skip)]
pub manifest_snapshot: super::manifest_snapshot::ManifestSnapshot,
}
#[derive(Clone)]
pub struct BuildProgressCallback(pub std::sync::Arc<dyn Fn(BuildProgressEvent) + Send + Sync>);
impl std::fmt::Debug for BuildProgressCallback {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "BuildProgressCallback")
}
}
#[derive(Debug, Clone)]
pub enum BuildProgressEvent {
InitTotal { total: usize, cached: usize },
Compiling(String),
UnitFinished,
CompilerMessage(String),
Diagnostic(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum BuildMode {
#[default]
Build,
Check,
Clippy,
Test,
}
#[derive(Debug, Clone, Default)]
pub struct RustBuildOptions {
pub manifest_path: Option<PathBuf>,
pub package: Option<String>,
pub packages: Vec<String>,
pub release: bool,
pub target_dir: Option<PathBuf>,
pub features: Vec<String>,
pub no_default_features: bool,
pub all_features: bool,
pub extra_args: Vec<String>,
pub no_cache: bool,
pub cache_dir: Option<PathBuf>,
pub offline: bool,
pub locked: bool,
pub frozen: bool,
pub example_targets: Vec<String>,
pub target_triple: Option<String>,
pub crate_types: Vec<String>,
pub quiet: bool,
pub json_diagnostics: bool,
pub fast_lock: Option<bool>,
pub native: bool,
pub cargo: bool,
pub verbose: u8,
pub mode: BuildMode,
pub progress: Option<BuildProgressCallback>,
pub start_dir: Option<PathBuf>,
pub test_targets: Vec<String>,
pub all_tests: bool,
pub all_benches: bool,
pub bench_targets: Vec<String>,
pub all_examples: bool,
pub bin_targets: Vec<String>,
pub all_bins: bool,
pub lib_only: bool,
pub doc_only: bool,
pub exclude: Vec<String>,
}
impl RustBuildOptions {
pub fn selected_package_names(&self) -> impl Iterator<Item = &str> {
self.package
.iter()
.chain(self.packages.iter())
.map(String::as_str)
}
pub fn selects_benches(&self) -> bool {
self.all_benches || !self.bench_targets.is_empty()
}
}
impl RustBuildOptions {
pub fn effective_compiler_args(&self) -> Vec<String> {
let mut args = if let Some(target) = self.target_triple.as_deref() {
let mut args = vec!["--target".to_string(), target.to_string()];
args.extend(self.extra_args.iter().cloned());
args
} else {
self.extra_args.clone()
};
if self.json_diagnostics {
args.push(JSON_DIAGNOSTICS_ARG.to_string());
}
args
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum EnvMacroDiscovery {
Tracked(Vec<String>),
UntrackedDynamic,
}