typed_path/platform.rs
1pub use self::non_utf8::*;
2pub use self::utf8::*;
3
4mod non_utf8 {
5 use crate::common::{CheckedPathError, Encoding, Path, PathBuf};
6 use crate::native::NativeEncoding;
7 use crate::no_std_compat::*;
8 use crate::private;
9 use core::any::TypeId;
10 use core::fmt;
11 use core::hash::Hasher;
12
13 /// [`Path`] that has the platform's encoding during compilation.
14 ///
15 /// # Examples
16 ///
17 /// ```
18 /// use typed_path::PlatformPath;
19 ///
20 /// // You can create the path like normal, but it is a distinct encoding from Unix/Windows
21 /// let path = PlatformPath::new("some/path");
22 ///
23 /// // The path will still behave like normal and even report its underlying encoding
24 /// assert_eq!(path.has_unix_encoding(), cfg!(unix));
25 /// assert_eq!(path.has_windows_encoding(), cfg!(windows));
26 ///
27 /// // It can still be converted into specific platform paths
28 /// let unix_path = path.with_unix_encoding();
29 /// let win_path = path.with_windows_encoding();
30 /// ```
31 pub type PlatformPath = Path<PlatformEncoding>;
32
33 /// [`PathBuf`] that has the platform's encoding during compilation.
34 ///
35 /// # Examples
36 ///
37 /// ```
38 /// use typed_path::PlatformPathBuf;
39 ///
40 /// // You can create the pathbuf like normal, but it is a distinct encoding from Unix/Windows
41 /// let path = PlatformPathBuf::from("some/path");
42 ///
43 /// // The path will still behave like normal and even report its underlying encoding
44 /// assert_eq!(path.has_unix_encoding(), cfg!(unix));
45 /// assert_eq!(path.has_windows_encoding(), cfg!(windows));
46 ///
47 /// // It can still be converted into specific platform paths
48 /// let unix_path = path.with_unix_encoding();
49 /// let win_path = path.with_windows_encoding();
50 /// ```
51 pub type PlatformPathBuf = PathBuf<PlatformEncoding>;
52
53 /// Represents an abstraction of [`Encoding`] that represents the current platform encoding.
54 ///
55 /// This differs from [`NativeEncoding`] in that it is its own struct instead of a type alias
56 /// to the platform-specific encoding, and can therefore be used to enforce more strict
57 /// compile-time checks of encodings without needing to leverage conditional configs.
58 ///
59 /// # Examples
60 ///
61 /// ```
62 /// use core::any::TypeId;
63 /// use typed_path::{PlatformEncoding, UnixEncoding, WindowsEncoding};
64 ///
65 /// // The platform encoding is considered a distinct type from Unix/Windows encodings.
66 /// assert_ne!(TypeId::of::<PlatformEncoding>(), TypeId::of::<UnixEncoding>());
67 /// assert_ne!(TypeId::of::<PlatformEncoding>(), TypeId::of::<WindowsEncoding>());
68 /// ```
69 #[derive(Copy, Clone)]
70 pub struct PlatformEncoding;
71
72 impl private::Sealed for PlatformEncoding {}
73
74 impl<'a> Encoding<'a> for PlatformEncoding {
75 type Components = <NativeEncoding as Encoding<'a>>::Components;
76
77 fn label() -> &'static str {
78 NativeEncoding::label()
79 }
80
81 fn components(path: &'a [u8]) -> Self::Components {
82 <NativeEncoding as Encoding<'a>>::components(path)
83 }
84
85 fn hash<H: Hasher>(path: &[u8], h: &mut H) {
86 <NativeEncoding as Encoding<'a>>::hash(path, h)
87 }
88
89 fn push(current_path: &mut Vec<u8>, path: &[u8]) {
90 <NativeEncoding as Encoding<'a>>::push(current_path, path);
91 }
92
93 fn push_checked(current_path: &mut Vec<u8>, path: &[u8]) -> Result<(), CheckedPathError> {
94 <NativeEncoding as Encoding<'a>>::push_checked(current_path, path)
95 }
96 }
97
98 impl fmt::Debug for PlatformEncoding {
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 f.debug_struct("PlatformEncoding").finish()
101 }
102 }
103
104 impl fmt::Display for PlatformEncoding {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 write!(f, "PlatformEncoding")
107 }
108 }
109
110 impl<T> Path<T>
111 where
112 T: for<'enc> Encoding<'enc> + 'static,
113 {
114 /// Returns true if the encoding is the platform abstraction ([`PlatformEncoding`]),
115 /// otherwise returns false.
116 ///
117 /// # Examples
118 ///
119 /// ```
120 /// use typed_path::{PlatformPath, UnixPath, WindowsPath};
121 ///
122 /// assert!(PlatformPath::new("/some/path").has_platform_encoding());
123 /// assert!(!UnixPath::new("/some/path").has_platform_encoding());
124 /// assert!(!WindowsPath::new("/some/path").has_platform_encoding());
125 /// ```
126 pub fn has_platform_encoding(&self) -> bool {
127 TypeId::of::<T>() == TypeId::of::<PlatformEncoding>()
128 }
129
130 /// Creates an owned [`PathBuf`] like `self` but using [`PlatformEncoding`].
131 ///
132 /// See [`Path::with_encoding`] for more information.
133 pub fn with_platform_encoding(&self) -> PathBuf<PlatformEncoding> {
134 self.with_encoding()
135 }
136
137 /// Creates an owned [`PathBuf`] like `self` but using [`PlatformEncoding`], ensuring it is
138 /// a valid platform path.
139 ///
140 /// See [`Path::with_encoding_checked`] for more information.
141 pub fn with_platform_encoding_checked(
142 &self,
143 ) -> Result<PathBuf<PlatformEncoding>, CheckedPathError> {
144 self.with_encoding_checked()
145 }
146 }
147}
148
149mod utf8 {
150 use crate::common::{CheckedPathError, Utf8Encoding, Utf8Path, Utf8PathBuf};
151 use crate::native::Utf8NativeEncoding;
152 use crate::no_std_compat::*;
153 use crate::private;
154 use core::any::TypeId;
155 use core::fmt;
156 use core::hash::Hasher;
157
158 #[cfg(feature = "std")]
159 use std::path::{Path as StdPath, PathBuf as StdPathBuf};
160
161 /// [`Utf8Path`] that has the platform's encoding during compilation.
162 ///
163 /// # Examples
164 ///
165 /// ```
166 /// use typed_path::Utf8PlatformPath;
167 ///
168 /// // You can create the path like normal, but it is a distinct encoding from Unix/Windows
169 /// let path = Utf8PlatformPath::new("some/path");
170 ///
171 /// // The path will still behave like normal and even report its underlying encoding
172 /// assert_eq!(path.has_unix_encoding(), cfg!(unix));
173 /// assert_eq!(path.has_windows_encoding(), cfg!(windows));
174 ///
175 /// // It can still be converted into specific platform paths
176 /// let unix_path = path.with_unix_encoding();
177 /// let win_path = path.with_windows_encoding();
178 /// ```
179 pub type Utf8PlatformPath = Utf8Path<Utf8PlatformEncoding>;
180
181 /// [`Utf8PathBuf`] that has the platform's encoding during compilation.
182 ///
183 /// # Examples
184 ///
185 /// ```
186 /// use typed_path::Utf8PlatformPathBuf;
187 ///
188 /// // You can create the pathbuf like normal, but it is a distinct encoding from Unix/Windows
189 /// let path = Utf8PlatformPathBuf::from("some/path");
190 ///
191 /// // The path will still behave like normal and even report its underlying encoding
192 /// assert_eq!(path.has_unix_encoding(), cfg!(unix));
193 /// assert_eq!(path.has_windows_encoding(), cfg!(windows));
194 ///
195 /// // It can still be converted into specific platform paths
196 /// let unix_path = path.with_unix_encoding();
197 /// let win_path = path.with_windows_encoding();
198 /// ```
199 pub type Utf8PlatformPathBuf = Utf8PathBuf<Utf8PlatformEncoding>;
200
201 /// Represents an abstraction of [`Utf8Encoding`] that represents the current platform
202 /// encoding.
203 ///
204 /// This differs from [`Utf8NativeEncoding`] in that it is its own struct instead of a type
205 /// alias to the platform-specific encoding, and can therefore be used to enforce more strict
206 /// compile-time checks of encodings without needing to leverage conditional configs.
207 ///
208 /// # Examples
209 ///
210 /// ```
211 /// use core::any::TypeId;
212 /// use typed_path::{Utf8PlatformEncoding, Utf8UnixEncoding, Utf8WindowsEncoding};
213 ///
214 /// // The UTF8 platform encoding is considered a distinct type from UTF8 Unix/Windows encodings.
215 /// assert_ne!(TypeId::of::<Utf8PlatformEncoding>(), TypeId::of::<Utf8UnixEncoding>());
216 /// assert_ne!(TypeId::of::<Utf8PlatformEncoding>(), TypeId::of::<Utf8WindowsEncoding>());
217 /// ```
218 #[derive(Copy, Clone)]
219 pub struct Utf8PlatformEncoding;
220
221 impl private::Sealed for Utf8PlatformEncoding {}
222
223 impl<'a> Utf8Encoding<'a> for Utf8PlatformEncoding {
224 type Components = <Utf8NativeEncoding as Utf8Encoding<'a>>::Components;
225
226 fn label() -> &'static str {
227 Utf8NativeEncoding::label()
228 }
229
230 fn components(path: &'a str) -> Self::Components {
231 <Utf8NativeEncoding as Utf8Encoding<'a>>::components(path)
232 }
233
234 fn hash<H: Hasher>(path: &str, h: &mut H) {
235 <Utf8NativeEncoding as Utf8Encoding<'a>>::hash(path, h)
236 }
237
238 fn push(current_path: &mut String, path: &str) {
239 <Utf8NativeEncoding as Utf8Encoding<'a>>::push(current_path, path);
240 }
241
242 fn push_checked(current_path: &mut String, path: &str) -> Result<(), CheckedPathError> {
243 <Utf8NativeEncoding as Utf8Encoding<'a>>::push_checked(current_path, path)
244 }
245 }
246
247 impl fmt::Debug for Utf8PlatformEncoding {
248 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
249 f.debug_struct("Utf8PlatformEncoding").finish()
250 }
251 }
252
253 impl fmt::Display for Utf8PlatformEncoding {
254 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255 write!(f, "Utf8PlatformEncoding")
256 }
257 }
258
259 impl<T> Utf8Path<T>
260 where
261 T: for<'enc> Utf8Encoding<'enc> + 'static,
262 {
263 /// Returns true if the encoding is the platform abstraction ([`Utf8PlatformEncoding`]),
264 /// otherwise returns false.
265 ///
266 /// # Examples
267 ///
268 /// ```
269 /// use typed_path::{Utf8PlatformPath, Utf8UnixPath, Utf8WindowsPath};
270 ///
271 /// assert!(Utf8PlatformPath::new("/some/path").has_platform_encoding());
272 /// assert!(!Utf8UnixPath::new("/some/path").has_platform_encoding());
273 /// assert!(!Utf8WindowsPath::new("/some/path").has_platform_encoding());
274 /// ```
275 pub fn has_platform_encoding(&self) -> bool {
276 TypeId::of::<T>() == TypeId::of::<Utf8PlatformEncoding>()
277 }
278
279 /// Creates an owned [`Utf8PathBuf`] like `self` but using [`Utf8PlatformEncoding`].
280 ///
281 /// See [`Utf8Path::with_encoding`] for more information.
282 pub fn with_platform_encoding(&self) -> Utf8PathBuf<Utf8PlatformEncoding> {
283 self.with_encoding()
284 }
285
286 /// Creates an owned [`Utf8PathBuf`] like `self` but using [`Utf8PlatformEncoding`],
287 /// ensuring it is a valid platform path.
288 ///
289 /// See [`Utf8Path::with_encoding_checked`] for more information.
290 pub fn with_platform_encoding_checked(
291 &self,
292 ) -> Result<Utf8PathBuf<Utf8PlatformEncoding>, CheckedPathError> {
293 self.with_encoding_checked()
294 }
295 }
296
297 #[cfg(all(feature = "std", not(target_family = "wasm")))]
298 impl AsRef<StdPath> for Utf8PlatformPath {
299 /// Converts a platform utf8 path (based on compilation family) into [`std::path::Path`].
300 ///
301 /// ```
302 /// use typed_path::Utf8PlatformPath;
303 /// use std::path::Path;
304 ///
305 /// let platform_path = Utf8PlatformPath::new("some_file.txt");
306 /// let std_path: &Path = platform_path.as_ref();
307 ///
308 /// assert_eq!(std_path, Path::new("some_file.txt"));
309 /// ```
310 fn as_ref(&self) -> &StdPath {
311 StdPath::new(self.as_str())
312 }
313 }
314
315 #[cfg(all(feature = "std", not(target_family = "wasm")))]
316 impl AsRef<StdPath> for Utf8PlatformPathBuf {
317 /// Converts a platform utf8 pathbuf (based on compilation family) into [`std::path::Path`].
318 ///
319 /// ```
320 /// use typed_path::Utf8PlatformPathBuf;
321 /// use std::path::Path;
322 ///
323 /// let platform_path_buf = Utf8PlatformPathBuf::from("some_file.txt");
324 /// let std_path: &Path = platform_path_buf.as_ref();
325 ///
326 /// assert_eq!(std_path, Path::new("some_file.txt"));
327 /// ```
328 fn as_ref(&self) -> &StdPath {
329 StdPath::new(self.as_str())
330 }
331 }
332
333 #[cfg(all(feature = "std", not(target_family = "wasm")))]
334 impl From<Utf8PlatformPathBuf> for StdPathBuf {
335 /// Converts a platform utf8 pathbuf (based on compilation family) into [`std::path::PathBuf`].
336 ///
337 /// ```
338 /// use typed_path::Utf8PlatformPathBuf;
339 /// use std::path::PathBuf;
340 ///
341 /// let platform_path_buf = Utf8PlatformPathBuf::from("some_file.txt");
342 /// let std_path_buf = PathBuf::from(platform_path_buf);
343 ///
344 /// assert_eq!(std_path_buf, PathBuf::from("some_file.txt"));
345 /// ```
346 fn from(utf8_platform_path_buf: Utf8PlatformPathBuf) -> StdPathBuf {
347 StdPathBuf::from(utf8_platform_path_buf.into_string())
348 }
349 }
350}