typed_path/
platform.rs

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