miden_diagnostics/
filename.rs

1use std::borrow::Cow;
2use std::fmt;
3use std::path::{Path, PathBuf};
4
5/// A [FileName] represents the name of a logical source code file,
6/// while retaining some context about whether that file is a real file on
7/// disk, or a "virtual" file, i.e. only exists in memory.
8#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
9pub enum FileName {
10    /// A real file on disk
11    Real(PathBuf),
12    /// A synthetic file, eg. from the REPL
13    Virtual(Cow<'static, str>),
14}
15impl From<PathBuf> for FileName {
16    fn from(name: PathBuf) -> FileName {
17        FileName::real(name)
18    }
19}
20impl From<FileName> for PathBuf {
21    fn from(name: FileName) -> PathBuf {
22        match name {
23            FileName::Real(path) => path,
24            FileName::Virtual(Cow::Owned(owned)) => PathBuf::from(owned),
25            FileName::Virtual(Cow::Borrowed(borrowed)) => PathBuf::from(borrowed),
26        }
27    }
28}
29impl<'a> From<&'a FileName> for &'a Path {
30    fn from(name: &'a FileName) -> &'a Path {
31        match *name {
32            FileName::Real(ref path) => path,
33            FileName::Virtual(ref cow) => Path::new(cow.as_ref()),
34        }
35    }
36}
37impl<'a> From<&'a Path> for FileName {
38    fn from(name: &Path) -> FileName {
39        FileName::real(name)
40    }
41}
42impl From<String> for FileName {
43    fn from(name: String) -> FileName {
44        FileName::virtual_(name)
45    }
46}
47impl From<&'static str> for FileName {
48    fn from(name: &'static str) -> FileName {
49        FileName::virtual_(name)
50    }
51}
52impl AsRef<Path> for FileName {
53    fn as_ref(&self) -> &Path {
54        match *self {
55            FileName::Real(ref path) => path.as_ref(),
56            FileName::Virtual(ref cow) => Path::new(cow.as_ref()),
57        }
58    }
59}
60impl PartialEq<Path> for FileName {
61    fn eq(&self, other: &Path) -> bool {
62        self.as_ref() == other
63    }
64}
65impl PartialEq<PathBuf> for FileName {
66    fn eq(&self, other: &PathBuf) -> bool {
67        self.as_ref() == other.as_path()
68    }
69}
70impl FileName {
71    /// Creates a new [FileName] that is intended to represent a real file on disk.
72    pub fn real<T: Into<PathBuf>>(name: T) -> FileName {
73        FileName::Real(name.into())
74    }
75
76    /// Creates a new [FileName] that is intended to represent a virtual file in memory.
77    pub fn virtual_<T: Into<Cow<'static, str>>>(name: T) -> FileName {
78        FileName::Virtual(name.into())
79    }
80
81    /// Returns true if this filename represents a real directory on disk
82    pub fn is_dir(&self) -> bool {
83        match self {
84            FileName::Real(ref path) => path.exists() && path.is_dir(),
85            _ => false,
86        }
87    }
88
89    /// Returns true if this filename represents a real file on disk
90    pub fn is_file(&self) -> bool {
91        match self {
92            FileName::Real(ref path) => path.exists() && path.is_file(),
93            _ => false,
94        }
95    }
96
97    /// Tries to return this filename as a `&str`, avoiding any allocations
98    ///
99    /// This will only return None if the filename is a path which requires lossy conversion to unicode.
100    /// See `to_string` if you want an infallible conversion to a Rust string, albeit at the cost of an allocation
101    pub fn as_str(&self) -> Option<&str> {
102        match self {
103            FileName::Real(ref path) => path.to_str(),
104            FileName::Virtual(Cow::Borrowed(s)) => Some(s),
105            FileName::Virtual(s) => Some(s.as_ref()),
106        }
107    }
108}
109impl fmt::Display for FileName {
110    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
111        match *self {
112            FileName::Real(ref path) => write!(fmt, "{}", path.display()),
113            FileName::Virtual(ref name) => write!(fmt, "<{}>", name),
114        }
115    }
116}