1#[derive(Clone, Debug, PartialEq, Eq, Hash, schemars::JsonSchema)]
5pub struct TypedPath(
6 #[cfg(target_arch = "wasm32")]
7 #[schemars(with = "String")]
8 pub typed_path::TypedPathBuf,
9 #[cfg(not(target_arch = "wasm32"))]
10 #[schemars(with = "String")]
11 pub std::path::PathBuf,
12);
13
14impl std::fmt::Display for TypedPath {
15 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16 #[cfg(target_arch = "wasm32")]
17 {
18 self.0.to_path().display().fmt(f)
19 }
20 #[cfg(not(target_arch = "wasm32"))]
21 {
22 self.0.display().fmt(f)
23 }
24 }
25}
26
27impl Default for TypedPath {
28 fn default() -> Self {
29 #[cfg(target_arch = "wasm32")]
30 {
31 TypedPath(typed_path::TypedPath::derive("").to_path_buf())
32 }
33 #[cfg(not(target_arch = "wasm32"))]
34 {
35 TypedPath(std::path::PathBuf::new())
36 }
37 }
38}
39
40impl From<&String> for TypedPath {
41 fn from(path: &String) -> Self {
42 TypedPath::new(path)
43 }
44}
45
46impl From<&str> for TypedPath {
47 fn from(path: &str) -> Self {
48 TypedPath::new(path)
49 }
50}
51
52impl TypedPath {
53 pub fn new(path: &str) -> Self {
54 #[cfg(target_arch = "wasm32")]
55 {
56 TypedPath(typed_path::TypedPath::derive(path).to_path_buf())
57 }
58 #[cfg(not(target_arch = "wasm32"))]
59 {
60 TypedPath(normalise_import(path))
61 }
62 }
63
64 pub fn starts_with(&self, base: &TypedPath) -> bool {
65 #[cfg(target_arch = "wasm32")]
66 {
67 self.0.starts_with(base.0.as_ref())
68 }
69 #[cfg(not(target_arch = "wasm32"))]
70 {
71 self.0.starts_with(&base.0)
72 }
73 }
74
75 pub fn extension(&self) -> Option<&str> {
76 #[cfg(target_arch = "wasm32")]
77 {
78 self.0
79 .extension()
80 .map(|s| std::str::from_utf8(s).map(|s| s.trim_start_matches('.')).unwrap_or(""))
81 .filter(|s| !s.is_empty())
82 }
83 #[cfg(not(target_arch = "wasm32"))]
84 {
85 self.0.extension().and_then(|s| s.to_str())
86 }
87 }
88
89 pub fn is_absolute(&self) -> bool {
90 self.0.is_absolute()
91 }
92
93 pub fn join(&self, path: &str) -> Self {
94 #[cfg(target_arch = "wasm32")]
95 {
96 TypedPath(self.0.join(path))
97 }
98 #[cfg(not(target_arch = "wasm32"))]
99 {
100 TypedPath(self.0.join(path))
101 }
102 }
103
104 pub fn join_typed(&self, path: &TypedPath) -> Self {
105 #[cfg(target_arch = "wasm32")]
106 {
107 TypedPath(self.0.join(path.0.to_path()))
108 }
109 #[cfg(not(target_arch = "wasm32"))]
110 {
111 TypedPath(self.0.join(&path.0))
112 }
113 }
114
115 pub fn parent(&self) -> Option<Self> {
116 #[cfg(target_arch = "wasm32")]
117 {
118 self.0.parent().map(|p| TypedPath(p.to_path_buf()))
119 }
120 #[cfg(not(target_arch = "wasm32"))]
121 {
122 self.0.parent().map(|p| TypedPath(p.to_path_buf()))
123 }
124 }
125
126 #[cfg(not(target_arch = "wasm32"))]
127 pub fn strip_prefix(&self, base: impl AsRef<std::path::Path>) -> Result<Self, std::path::StripPrefixError> {
128 self.0.strip_prefix(base).map(|p| TypedPath(p.to_path_buf()))
129 }
130
131 #[cfg(not(target_arch = "wasm32"))]
132 pub fn canonicalize(&self) -> Result<Self, std::io::Error> {
133 self.0.canonicalize().map(TypedPath)
134 }
135
136 pub fn to_string_lossy(&self) -> String {
137 #[cfg(target_arch = "wasm32")]
138 {
139 self.0.to_path().to_string_lossy().to_string()
140 }
141 #[cfg(not(target_arch = "wasm32"))]
142 {
143 self.0.to_string_lossy().to_string()
144 }
145 }
146
147 pub fn display(&self) -> String {
148 #[cfg(target_arch = "wasm32")]
149 {
150 self.0.to_path().display().to_string()
151 }
152 #[cfg(not(target_arch = "wasm32"))]
153 {
154 self.0.display().to_string()
155 }
156 }
157
158 pub fn file_name(&self) -> Option<String> {
159 #[cfg(target_arch = "wasm32")]
160 {
161 self.0
162 .file_name()
163 .map(|s| std::str::from_utf8(s).unwrap_or(""))
164 .filter(|s| !s.is_empty())
165 .map(|s| s.to_string())
166 }
167 #[cfg(not(target_arch = "wasm32"))]
168 {
169 self.0.file_name().and_then(|s| s.to_str()).map(|s| s.to_string())
170 }
171 }
172}
173
174impl serde::Serialize for TypedPath {
175 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
176 where
177 S: serde::Serializer,
178 {
179 #[cfg(target_arch = "wasm32")]
180 {
181 self.0.to_str().serialize(serializer)
182 }
183 #[cfg(not(target_arch = "wasm32"))]
184 {
185 self.0.serialize(serializer)
186 }
187 }
188}
189
190impl<'de> serde::de::Deserialize<'de> for TypedPath {
191 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
192 where
193 D: serde::Deserializer<'de>,
194 {
195 #[cfg(target_arch = "wasm32")]
196 {
197 let path: String = serde::Deserialize::deserialize(deserializer)?;
198 Ok(TypedPath(typed_path::TypedPath::derive(&path).to_path_buf()))
199 }
200 #[cfg(not(target_arch = "wasm32"))]
201 {
202 let path: std::path::PathBuf = serde::Deserialize::deserialize(deserializer)?;
203 Ok(TypedPath(path))
204 }
205 }
206}
207
208impl ts_rs::TS for TypedPath {
209 type WithoutGenerics = Self;
210 type OptionInnerType = Self;
211
212 fn name(_: &ts_rs::Config) -> String {
213 "string".to_string()
214 }
215
216 fn decl(config: &ts_rs::Config) -> String {
217 std::path::PathBuf::decl(config)
218 }
219
220 fn decl_concrete(config: &ts_rs::Config) -> String {
221 std::path::PathBuf::decl_concrete(config)
222 }
223
224 fn inline(config: &ts_rs::Config) -> String {
225 std::path::PathBuf::inline(config)
226 }
227
228 fn inline_flattened(config: &ts_rs::Config) -> String {
229 std::path::PathBuf::inline_flattened(config)
230 }
231
232 fn output_path() -> Option<std::path::PathBuf> {
233 std::path::PathBuf::output_path()
234 }
235}
236
237#[cfg(not(target_arch = "wasm32"))]
243fn normalise_import<S: AsRef<str>>(raw: S) -> std::path::PathBuf {
244 let s = raw.as_ref();
245 if cfg!(unix) && s.contains('\\') {
248 std::path::PathBuf::from(s.replace('\\', "/"))
249 } else {
250 std::path::Path::new(s).to_path_buf()
251 }
252}