assay_core/config/
path_resolver.rs1use std::path::{Path, PathBuf};
2
3#[derive(Clone)]
4pub struct PathResolver {
5 base_dir: PathBuf,
6}
7
8impl PathResolver {
9 pub fn new(config_path: &Path) -> Self {
10 let base_dir = config_path.parent().unwrap_or(Path::new(".")).to_path_buf();
11 Self { base_dir }
12 }
13
14 pub fn resolve_opt_str(&self, p: &mut Option<String>) {
15 let Some(s) = p.as_mut() else { return };
16 if s.trim().is_empty() {
17 return;
18 }
19
20 let pb = PathBuf::from(&*s);
21 if pb.is_absolute() {
22 return;
23 }
24
25 let joined = self.join_clean(&pb);
26 *s = joined.to_string_lossy().to_string();
27 }
28
29 pub fn resolve_str(&self, s: &mut String) {
30 if s.trim().is_empty() {
31 return;
32 }
33 let pb = PathBuf::from(&*s);
34 if pb.is_absolute() {
35 return;
36 }
37
38 let joined = self.join_clean(&pb);
39 *s = joined.to_string_lossy().to_string();
40 }
41
42 fn join_clean(&self, rel: &Path) -> PathBuf {
43 let joined = self.base_dir.join(rel);
44
45 let mut out = PathBuf::new();
46 for c in joined.components() {
47 use std::path::Component::*;
48 match c {
49 CurDir => {}
50 ParentDir => {
51 out.pop();
52 }
53 RootDir | Prefix(_) | Normal(_) => out.push(c.as_os_str()),
54 }
55 }
56 out
57 }
58}