use std::collections::HashSet;
use std::path::{Path, PathBuf};
use super::ConfigDiscovery;
use super::telemetry;
#[cfg(windows)]
fn windows_normalized_key(path: &Path) -> Vec<u16> {
use std::os::windows::ffi::OsStrExt;
path.as_os_str()
.encode_wide()
.map(|unit| match unit {
65..=90 => unit + 32,
47 => 92,
_ => unit,
})
.collect()
}
impl ConfigDiscovery {
pub(super) fn dedup_key(path: &Path) -> DedupKey {
#[cfg(windows)]
{
windows_normalized_key(path)
}
#[cfg(not(windows))]
{
path.as_os_str().to_os_string()
}
}
#[cfg(all(test, windows))]
pub(super) fn normalized_key(path: &Path) -> DedupKey {
Self::dedup_key(path)
}
}
#[cfg(windows)]
pub(super) type DedupKey = Vec<u16>;
#[cfg(not(windows))]
pub(super) type DedupKey = std::ffi::OsString;
pub(super) struct Candidate {
pub(super) path: PathBuf,
pub(super) source: &'static str,
}
#[derive(Default)]
pub(super) struct CandidateAccumulator {
pub(super) candidates: Vec<Candidate>,
seen: HashSet<DedupKey>,
}
impl CandidateAccumulator {
pub(super) fn push_unique(&mut self, candidate: PathBuf, source: &'static str) -> bool {
if candidate.as_os_str().is_empty() {
return false;
}
let key = ConfigDiscovery::dedup_key(&candidate);
if self.seen.insert(key) {
self.candidates.push(Candidate {
path: candidate,
source,
});
true
} else {
false
}
}
}
pub(super) struct CandidateDecisions {
pub(super) selector: &'static str,
pub(super) xdg_config_home: &'static str,
pub(super) xdg_dirs: &'static str,
pub(super) xdg_resolution: &'static str,
pub(super) home: &'static str,
}
impl CandidateDecisions {
pub(super) fn emit(&self) {
telemetry::selector_decision(self.selector);
telemetry::xdg_decision(self.xdg_config_home, self.xdg_dirs, self.xdg_resolution);
telemetry::home_decision(self.home);
}
}
pub(super) struct CandidateSet {
pub(super) candidates: Vec<Candidate>,
pub(super) required_bound: usize,
pub(super) decisions: CandidateDecisions,
}