Skip to main content

ruff_db/files/
path.rs

1use crate::Db;
2use crate::files::{File, system_path_to_file, vendored_path_to_file};
3use crate::system::{SystemPath, SystemPathBuf, SystemVirtualPath, SystemVirtualPathBuf};
4use crate::vendored::{VendoredPath, VendoredPathBuf};
5use std::fmt::{Display, Formatter};
6
7/// Path to a file.
8///
9/// The path abstracts that files in Ruff can come from different sources:
10///
11/// * a file stored on the [host system](crate::system::System).
12/// * a virtual file stored on the [host system](crate::system::System).
13/// * a vendored file stored in the [vendored file system](crate::vendored::VendoredFileSystem).
14#[derive(Clone, Debug, Eq, PartialEq, Hash, get_size2::GetSize)]
15pub enum FilePath {
16    /// Path to a file on the [host system](crate::system::System).
17    System(Box<SystemPath>),
18    /// Path to a virtual file on the [host system](crate::system::System).
19    SystemVirtual(Box<SystemVirtualPath>),
20    /// Path to a file vendored as part of Ruff. Stored in the [vendored file system](crate::vendored::VendoredFileSystem).
21    Vendored(Box<VendoredPath>),
22}
23
24impl FilePath {
25    /// Create a new path to a file on the file system.
26    #[must_use]
27    pub fn system(path: impl AsRef<SystemPath>) -> Self {
28        FilePath::from(path.as_ref())
29    }
30
31    #[must_use]
32    #[inline]
33    pub fn as_system_path(&self) -> Option<&SystemPath> {
34        match self {
35            FilePath::System(path) => Some(path),
36            FilePath::Vendored(_) | FilePath::SystemVirtual(_) => None,
37        }
38    }
39
40    /// Returns `true` if the path is a file system path that points to a path on disk.
41    #[must_use]
42    #[inline]
43    pub const fn is_system_path(&self) -> bool {
44        matches!(self, FilePath::System(_))
45    }
46
47    /// Returns `true` if the path is a file system path that is virtual i.e., it doesn't exists on
48    /// disk.
49    #[must_use]
50    #[inline]
51    pub const fn is_system_virtual_path(&self) -> bool {
52        matches!(self, FilePath::SystemVirtual(_))
53    }
54
55    /// Returns `true` if the path is a vendored path.
56    #[must_use]
57    #[inline]
58    pub const fn is_vendored_path(&self) -> bool {
59        matches!(self, FilePath::Vendored(_))
60    }
61
62    #[must_use]
63    #[inline]
64    pub fn as_vendored_path(&self) -> Option<&VendoredPath> {
65        match self {
66            FilePath::Vendored(path) => Some(path),
67            FilePath::System(_) | FilePath::SystemVirtual(_) => None,
68        }
69    }
70
71    /// Yields the underlying [`str`] slice.
72    pub fn as_str(&self) -> &str {
73        match self {
74            FilePath::System(path) => path.as_str(),
75            FilePath::Vendored(path) => path.as_str(),
76            FilePath::SystemVirtual(path) => path.as_str(),
77        }
78    }
79
80    /// Interns a virtual file system path and returns a salsa [`File`] ingredient.
81    ///
82    /// Returns `Some` if a file for `path` exists and is accessible by the user. Returns `None` otherwise.
83    ///
84    /// See [`system_path_to_file`] or [`vendored_path_to_file`] if you always have either a file
85    /// system or vendored path.
86    #[inline]
87    pub fn to_file(&self, db: &dyn Db) -> Option<File> {
88        match self {
89            FilePath::System(path) => system_path_to_file(db, path).ok(),
90            FilePath::Vendored(path) => vendored_path_to_file(db, path).ok(),
91            FilePath::SystemVirtual(_) => None,
92        }
93    }
94
95    #[must_use]
96    pub fn extension(&self) -> Option<&str> {
97        match self {
98            FilePath::System(path) => path.extension(),
99            FilePath::Vendored(path) => path.extension(),
100            FilePath::SystemVirtual(_) => None,
101        }
102    }
103}
104
105impl AsRef<str> for FilePath {
106    fn as_ref(&self) -> &str {
107        self.as_str()
108    }
109}
110
111impl From<SystemPathBuf> for FilePath {
112    fn from(value: SystemPathBuf) -> Self {
113        Self::System(Box::from(value))
114    }
115}
116
117impl From<&SystemPath> for FilePath {
118    fn from(value: &SystemPath) -> Self {
119        Self::System(Box::from(value))
120    }
121}
122
123impl From<VendoredPathBuf> for FilePath {
124    fn from(value: VendoredPathBuf) -> Self {
125        Self::Vendored(Box::from(value))
126    }
127}
128
129impl From<&VendoredPath> for FilePath {
130    fn from(value: &VendoredPath) -> Self {
131        Self::Vendored(Box::from(value))
132    }
133}
134
135impl From<&SystemVirtualPath> for FilePath {
136    fn from(value: &SystemVirtualPath) -> Self {
137        Self::SystemVirtual(Box::from(value))
138    }
139}
140
141impl From<SystemVirtualPathBuf> for FilePath {
142    fn from(value: SystemVirtualPathBuf) -> Self {
143        Self::SystemVirtual(Box::from(value))
144    }
145}
146
147impl PartialEq<SystemPath> for FilePath {
148    #[inline]
149    fn eq(&self, other: &SystemPath) -> bool {
150        self.as_system_path()
151            .is_some_and(|self_path| self_path == other)
152    }
153}
154
155impl PartialEq<FilePath> for SystemPath {
156    #[inline]
157    fn eq(&self, other: &FilePath) -> bool {
158        other == self
159    }
160}
161
162impl PartialEq<SystemPathBuf> for FilePath {
163    #[inline]
164    fn eq(&self, other: &SystemPathBuf) -> bool {
165        self == other.as_path()
166    }
167}
168
169impl PartialEq<FilePath> for SystemPathBuf {
170    fn eq(&self, other: &FilePath) -> bool {
171        other == self
172    }
173}
174
175impl PartialEq<VendoredPath> for FilePath {
176    #[inline]
177    fn eq(&self, other: &VendoredPath) -> bool {
178        self.as_vendored_path()
179            .is_some_and(|self_path| self_path == other)
180    }
181}
182
183impl PartialEq<FilePath> for VendoredPath {
184    #[inline]
185    fn eq(&self, other: &FilePath) -> bool {
186        other == self
187    }
188}
189
190impl PartialEq<VendoredPathBuf> for FilePath {
191    #[inline]
192    fn eq(&self, other: &VendoredPathBuf) -> bool {
193        other.as_path() == self
194    }
195}
196
197impl PartialEq<FilePath> for VendoredPathBuf {
198    #[inline]
199    fn eq(&self, other: &FilePath) -> bool {
200        other == self
201    }
202}
203
204impl Display for FilePath {
205    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
206        match self {
207            FilePath::System(path) => std::fmt::Display::fmt(path, f),
208            FilePath::SystemVirtual(path) => std::fmt::Display::fmt(path, f),
209            FilePath::Vendored(path) => std::fmt::Display::fmt(path, f),
210        }
211    }
212}