use std::path::{Path, PathBuf};
use crate::probe::{Toolbox, Version};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Origin {
Override,
Path,
Sibling,
}
impl Origin {
pub fn token(self) -> &'static str {
match self {
Origin::Override => "override",
Origin::Path => "path",
Origin::Sibling => "sibling",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Skew {
Match,
Minor,
Major,
}
impl Skew {
pub fn classify(driver: Version, compiler: Version) -> Skew {
if driver.major != compiler.major {
Skew::Major
} else if driver.minor != compiler.minor {
Skew::Minor
} else {
Skew::Match
}
}
pub fn token(self) -> &'static str {
match self {
Skew::Match => "match",
Skew::Minor => "minor",
Skew::Major => "major",
}
}
}
#[derive(Debug, Clone)]
pub struct Compiler {
pub path: Option<PathBuf>,
pub origin: Option<Origin>,
pub version: Option<Version>,
pub skew: Option<Skew>,
}
impl Compiler {
pub fn is_resolved(&self) -> bool {
self.path.is_some()
}
pub fn has_major_skew(&self) -> bool {
self.skew == Some(Skew::Major)
}
}
pub fn resolve(
tb: &dyn Toolbox,
override_path: Option<&Path>,
bynk_bin_dir: Option<&Path>,
driver: Version,
) -> Compiler {
let (path, origin) = locate(tb, override_path, bynk_bin_dir);
let version = path.as_deref().and_then(|p| tb.version(p));
let skew = version.map(|v| Skew::classify(driver, v));
Compiler {
path,
origin,
version,
skew,
}
}
fn locate(
tb: &dyn Toolbox,
override_path: Option<&Path>,
bynk_bin_dir: Option<&Path>,
) -> (Option<PathBuf>, Option<Origin>) {
if let Some(ovr) = override_path {
if let Some(p) = tb.in_dir(ovr.parent().unwrap_or(Path::new(".")), file_stem(ovr)) {
return (Some(p), Some(Origin::Override));
}
return (Some(ovr.to_path_buf()), Some(Origin::Override));
}
if let Some(p) = tb.on_path("bynkc") {
return (Some(p), Some(Origin::Path));
}
if let Some(dir) = bynk_bin_dir
&& let Some(p) = tb.in_dir(dir, "bynkc")
{
return (Some(p), Some(Origin::Sibling));
}
(None, None)
}
fn file_stem(p: &Path) -> &str {
p.file_stem().and_then(|s| s.to_str()).unwrap_or("bynkc")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn skew_classification() {
let v = |a, b, c| Version {
major: a,
minor: b,
patch: c,
};
assert_eq!(Skew::classify(v(0, 46, 0), v(0, 46, 0)), Skew::Match);
assert_eq!(Skew::classify(v(0, 46, 0), v(0, 46, 3)), Skew::Match);
assert_eq!(Skew::classify(v(0, 46, 0), v(0, 44, 0)), Skew::Minor);
assert_eq!(Skew::classify(v(1, 0, 0), v(0, 46, 0)), Skew::Major);
}
}