kcl_lib/execution/
typed_path.rs

1//! A typed path type so that in wasm we can track if its a windows or unix path.
2//! On non-wasm platforms, this is just a std::path::PathBuf.
3
4#[derive(Clone, Debug, PartialEq, Eq, Hash)]
5pub struct TypedPath(
6    #[cfg(target_arch = "wasm32")] pub typed_path::TypedPathBuf,
7    #[cfg(not(target_arch = "wasm32"))] pub std::path::PathBuf,
8);
9
10impl std::fmt::Display for TypedPath {
11    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12        #[cfg(target_arch = "wasm32")]
13        {
14            self.0.to_path().display().fmt(f)
15        }
16        #[cfg(not(target_arch = "wasm32"))]
17        {
18            self.0.display().fmt(f)
19        }
20    }
21}
22
23impl Default for TypedPath {
24    fn default() -> Self {
25        #[cfg(target_arch = "wasm32")]
26        {
27            TypedPath(typed_path::TypedPath::derive("").to_path_buf())
28        }
29        #[cfg(not(target_arch = "wasm32"))]
30        {
31            TypedPath(std::path::PathBuf::new())
32        }
33    }
34}
35
36impl From<&String> for TypedPath {
37    fn from(path: &String) -> Self {
38        #[cfg(target_arch = "wasm32")]
39        {
40            TypedPath(typed_path::TypedPath::derive(path).to_path_buf())
41        }
42        #[cfg(not(target_arch = "wasm32"))]
43        {
44            TypedPath(std::path::PathBuf::from(path))
45        }
46    }
47}
48
49impl From<&str> for TypedPath {
50    fn from(path: &str) -> Self {
51        #[cfg(target_arch = "wasm32")]
52        {
53            TypedPath(typed_path::TypedPath::derive(path).to_path_buf())
54        }
55        #[cfg(not(target_arch = "wasm32"))]
56        {
57            TypedPath(std::path::PathBuf::from(path))
58        }
59    }
60}
61
62impl TypedPath {
63    pub fn extension(&self) -> Option<&str> {
64        #[cfg(target_arch = "wasm32")]
65        {
66            self.0
67                .extension()
68                .map(|s| std::str::from_utf8(s).map(|s| s.trim_start_matches('.')).unwrap_or(""))
69                .filter(|s| !s.is_empty())
70        }
71        #[cfg(not(target_arch = "wasm32"))]
72        {
73            self.0.extension().and_then(|s| s.to_str())
74        }
75    }
76
77    pub fn join(&self, path: &str) -> Self {
78        #[cfg(target_arch = "wasm32")]
79        {
80            TypedPath(self.0.join(path))
81        }
82        #[cfg(not(target_arch = "wasm32"))]
83        {
84            TypedPath(self.0.join(path))
85        }
86    }
87
88    pub fn parent(&self) -> Option<Self> {
89        #[cfg(target_arch = "wasm32")]
90        {
91            self.0.parent().map(|p| TypedPath(p.to_path_buf()))
92        }
93        #[cfg(not(target_arch = "wasm32"))]
94        {
95            self.0.parent().map(|p| TypedPath(p.to_path_buf()))
96        }
97    }
98
99    pub fn to_string_lossy(&self) -> String {
100        #[cfg(target_arch = "wasm32")]
101        {
102            self.0.to_path().to_string_lossy().to_string()
103        }
104        #[cfg(not(target_arch = "wasm32"))]
105        {
106            self.0.to_string_lossy().to_string()
107        }
108    }
109
110    pub fn display(&self) -> String {
111        #[cfg(target_arch = "wasm32")]
112        {
113            self.0.to_path().display().to_string()
114        }
115        #[cfg(not(target_arch = "wasm32"))]
116        {
117            self.0.display().to_string()
118        }
119    }
120
121    pub fn file_name(&self) -> Option<String> {
122        #[cfg(target_arch = "wasm32")]
123        {
124            self.0
125                .file_name()
126                .map(|s| std::str::from_utf8(s).unwrap_or(""))
127                .filter(|s| !s.is_empty())
128                .map(|s| s.to_string())
129        }
130        #[cfg(not(target_arch = "wasm32"))]
131        {
132            self.0.file_name().and_then(|s| s.to_str()).map(|s| s.to_string())
133        }
134    }
135}
136
137impl serde::Serialize for TypedPath {
138    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
139    where
140        S: serde::Serializer,
141    {
142        #[cfg(target_arch = "wasm32")]
143        {
144            self.0.to_str().serialize(serializer)
145        }
146        #[cfg(not(target_arch = "wasm32"))]
147        {
148            self.0.serialize(serializer)
149        }
150    }
151}
152
153impl<'de> serde::de::Deserialize<'de> for TypedPath {
154    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
155    where
156        D: serde::Deserializer<'de>,
157    {
158        #[cfg(target_arch = "wasm32")]
159        {
160            let path: String = serde::Deserialize::deserialize(deserializer)?;
161            Ok(TypedPath(typed_path::TypedPath::derive(&path).to_path_buf()))
162        }
163        #[cfg(not(target_arch = "wasm32"))]
164        {
165            let path: std::path::PathBuf = serde::Deserialize::deserialize(deserializer)?;
166            Ok(TypedPath(path))
167        }
168    }
169}
170
171impl ts_rs::TS for TypedPath {
172    type WithoutGenerics = Self;
173
174    fn name() -> String {
175        "string".to_string()
176    }
177
178    fn decl() -> String {
179        std::path::PathBuf::decl()
180    }
181
182    fn decl_concrete() -> String {
183        std::path::PathBuf::decl_concrete()
184    }
185
186    fn inline() -> String {
187        std::path::PathBuf::inline()
188    }
189
190    fn inline_flattened() -> String {
191        std::path::PathBuf::inline_flattened()
192    }
193
194    fn output_path() -> Option<&'static std::path::Path> {
195        std::path::PathBuf::output_path()
196    }
197}
198
199impl schemars::JsonSchema for TypedPath {
200    fn schema_name() -> String {
201        "TypedPath".to_owned()
202    }
203
204    fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
205        // TODO: Actually generate a reasonable schema.
206        gen.subschema_for::<std::path::PathBuf>()
207    }
208}