1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
use std::fmt::Formatter;
use std::path::{Path, PathBuf};

use crate::code_source::CodeSource;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CodePath {
    ToFile(PathBuf),
    ToMemory(String),
}

#[derive(Debug)]
pub struct FileRelative<T> {
    pub value: T,
    pub filepath: CodePath,
}

impl CodeSource {
    pub fn with_filename<T>(&self, f: impl Fn(&Self) -> T) -> FileRelative<T> {
        FileRelative {
            value: f(self),
            filepath: self.path(),
        }
    }

    #[must_use]
    pub fn path(&self) -> CodePath {
        match self {
            CodeSource::Memory { name, .. } => CodePath::ToMemory(name.clone()),
            CodeSource::File { name, .. } => CodePath::ToFile(name.clone()),
        }
    }
}

impl<T> FileRelative<T> {
    pub fn map<V>(self, f: impl FnOnce(T) -> V) -> FileRelative<V> {
        FileRelative {
            value: f(self.value),
            filepath: self.filepath,
        }
    }
}

impl CodePath {
    pub fn get_relative_path<P: AsRef<Path> + ?Sized>(&self, base: &P) -> CodePath {
        match self {
            CodePath::ToFile(p) => {
                CodePath::ToFile(pathdiff::diff_paths(p, base).unwrap_or(p.clone()))
            }
            CodePath::ToMemory(s) => CodePath::ToMemory(s.clone()),
        }
    }
}

impl std::fmt::Display for CodePath {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            CodePath::ToFile(p) => write!(f, "{0}", p.display()),
            CodePath::ToMemory(p) => write!(f, "{p}"),
        }
    }
}