Skip to main content

strict_path/path/virtual_path/
traits.rs

1//! Standard trait impls for `VirtualPath`: `Display`, `Debug`, `PartialEq`, `Eq`,
2//! `PartialOrd`, `Ord`, `Hash`, and cross-type comparisons with `StrictPath`.
3//!
4//! `Display` shows the virtual path (rooted, forward-slash). `Debug` is verbose by design:
5//! it exposes both the virtual view and the real system path so developers can trace
6//! the full picture during debugging without accidentally leaking it in production output.
7use super::VirtualPath;
8use std::fmt;
9use std::hash::{Hash, Hasher};
10use std::path::Path;
11
12impl<Marker> fmt::Debug for VirtualPath<Marker> {
13    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
14        f.debug_struct("VirtualPath")
15            .field("system_path", &self.inner.path())
16            .field("virtual", &self.virtualpath_display().to_string())
17            .field("boundary", &self.inner.boundary().path())
18            .field("marker", &std::any::type_name::<Marker>())
19            .finish()
20    }
21}
22
23impl<Marker> PartialEq for VirtualPath<Marker> {
24    #[inline]
25    fn eq(&self, other: &Self) -> bool {
26        self.inner.path() == other.inner.path()
27    }
28}
29
30impl<Marker> Eq for VirtualPath<Marker> {}
31
32impl<Marker> Hash for VirtualPath<Marker> {
33    #[inline]
34    fn hash<H: Hasher>(&self, state: &mut H) {
35        self.inner.path().hash(state);
36    }
37}
38
39impl<Marker> PartialEq<crate::path::strict_path::StrictPath<Marker>> for VirtualPath<Marker> {
40    #[inline]
41    fn eq(&self, other: &crate::path::strict_path::StrictPath<Marker>) -> bool {
42        self.inner.path() == other.path()
43    }
44}
45
46impl<T: AsRef<Path>, Marker> PartialEq<T> for VirtualPath<Marker> {
47    #[inline]
48    fn eq(&self, other: &T) -> bool {
49        // Compare virtual paths - the user-facing representation
50        // If you want system path comparison, use as_unvirtual()
51        let virtual_str = self.virtualpath_display().to_string();
52        let other_str = other.as_ref().to_string_lossy();
53
54        // Normalize both to forward slashes and ensure leading slash
55        let normalized_virtual = virtual_str.as_str();
56
57        #[cfg(windows)]
58        let other_normalized = other_str.replace('\\', "/");
59        #[cfg(not(windows))]
60        let other_normalized = other_str.to_string();
61
62        let normalized_other = if other_normalized.starts_with('/') {
63            other_normalized
64        } else {
65            format!("/{other_normalized}")
66        };
67
68        normalized_virtual == normalized_other
69    }
70}
71
72impl<T: AsRef<Path>, Marker> PartialOrd<T> for VirtualPath<Marker> {
73    #[inline]
74    fn partial_cmp(&self, other: &T) -> Option<std::cmp::Ordering> {
75        // Compare virtual paths - the user-facing representation
76        let virtual_str = self.virtualpath_display().to_string();
77        let other_str = other.as_ref().to_string_lossy();
78
79        // Normalize both to forward slashes and ensure leading slash
80        let normalized_virtual = virtual_str.as_str();
81
82        #[cfg(windows)]
83        let other_normalized = other_str.replace('\\', "/");
84        #[cfg(not(windows))]
85        let other_normalized = other_str.to_string();
86
87        let normalized_other = if other_normalized.starts_with('/') {
88            other_normalized
89        } else {
90            format!("/{other_normalized}")
91        };
92
93        Some(normalized_virtual.cmp(&normalized_other))
94    }
95}
96
97impl<Marker> PartialOrd for VirtualPath<Marker> {
98    #[inline]
99    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
100        Some(self.cmp(other))
101    }
102}
103
104impl<Marker> Ord for VirtualPath<Marker> {
105    #[inline]
106    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
107        self.inner.path().cmp(other.inner.path())
108    }
109}