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}