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}