serde_hkx_features/convert/
mod.rs
1pub mod rayon;
2pub mod tokio;
3
4use crate::error::{Error, Result};
5use parse_display::{Display, FromStr};
6use std::{
7 ffi::OsStr,
8 path::{Path, PathBuf},
9};
10
11#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
16#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Display, FromStr)]
17#[display(style = "camelCase")]
18#[non_exhaustive]
19pub enum OutFormat {
20 #[default]
22 Amd64,
23 Win32,
25 Xml,
27
28 #[cfg(feature = "extra_fmt")]
29 Json,
31 #[cfg(feature = "extra_fmt")]
32 Toml,
34 #[cfg(feature = "extra_fmt")]
35 Yaml,
37}
38
39impl OutFormat {
40 #[inline]
51 pub const fn as_extension(&self) -> &str {
52 match *self {
53 Self::Amd64 => "hkx",
54 Self::Win32 => "hkx",
55 Self::Xml => "xml",
56
57 #[cfg(feature = "extra_fmt")]
58 Self::Json => "json",
59 #[cfg(feature = "extra_fmt")]
60 Self::Toml => "toml",
61 #[cfg(feature = "extra_fmt")]
62 Self::Yaml => "yaml",
63 }
64 }
65
66 #[inline]
82 pub fn from_input<P>(path: P) -> Result<Self>
83 where
84 P: AsRef<Path>,
85 {
86 let path = path.as_ref();
87 let ext = path.extension().ok_or(Error::UnsupportedExtensionPath {
88 path: path.to_path_buf(),
89 })?;
90
91 Ok(match ext {
92 ext if ext.eq_ignore_ascii_case("hkx") => Self::Xml,
93 ext if ext.eq_ignore_ascii_case("xml") => Self::Amd64,
94
95 #[cfg(feature = "extra_fmt")]
96 ext if ext.eq_ignore_ascii_case("json") => Self::Amd64,
97 #[cfg(feature = "extra_fmt")]
98 ext if ext.eq_ignore_ascii_case("toml") => Self::Amd64,
99 #[cfg(feature = "extra_fmt")]
100 ext if ext.eq_ignore_ascii_case("yaml") || ext.eq_ignore_ascii_case("yml") => {
101 Self::Amd64
102 }
103 _ => {
104 return Err(Error::UnsupportedExtensionPath {
105 path: path.to_path_buf(),
106 });
107 }
108 })
109 }
110
111 #[inline]
129 pub fn from_extension<S>(ext: S) -> Result<Self>
130 where
131 S: AsRef<OsStr>,
132 {
133 let ext = ext.as_ref();
134 Ok(match ext {
135 ext if ext.eq_ignore_ascii_case("hkx") => Self::Amd64,
136 ext if ext.eq_ignore_ascii_case("xml") => Self::Xml,
137
138 #[cfg(feature = "extra_fmt")]
139 ext if ext.eq_ignore_ascii_case("json") => Self::Json,
140 #[cfg(feature = "extra_fmt")]
141 ext if ext.eq_ignore_ascii_case("toml") => Self::Toml,
142 #[cfg(feature = "extra_fmt")]
143 ext if ext.eq_ignore_ascii_case("yaml") || ext.eq_ignore_ascii_case("yml") => {
144 Self::Yaml
145 }
146 _ => {
147 return Err(Error::UnsupportedExtension {
148 ext: ext.to_string_lossy().to_string(),
149 });
150 }
151 })
152 }
153}
154
155fn get_output_path<D, I, O>(
159 input_dir: D,
160 input: I,
161 output_dir: &Option<O>,
162 format: OutFormat,
163) -> Option<PathBuf>
164where
165 D: AsRef<Path>,
166 I: AsRef<Path>,
167 O: AsRef<Path>,
168{
169 let input = input.as_ref();
170 let input_dir = input_dir.as_ref();
171
172 match output_dir {
173 Some(output_dir) => {
174 let input_inner_dir = input.strip_prefix(input_dir).ok()?;
175 let mut output = output_dir.as_ref().join(input_inner_dir);
176 output.set_extension(format.as_extension());
177 Some(output)
178 }
179 None => None,
180 }
181}
182
183fn filter_supported_files(entry: &jwalk::DirEntry<((), ())>) -> bool {
184 let path = entry.path();
185
186 if !path.is_file() {
187 return false;
188 }
189
190 path.extension()
191 .and_then(|ext| ext.to_str())
192 .is_some_and(|ext| {
193 if OutFormat::from_extension(ext).is_err() {
194 #[cfg(feature = "tracing")]
195 tracing::info!("Skip this unsupported extension: {}", path.display());
196 false
197 } else {
198 true
199 }
200 })
201}
202
203fn get_supported_files(input_dir: &Path) -> Vec<PathBuf> {
204 jwalk::WalkDir::new(input_dir)
205 .into_iter()
206 .filter_map(|entry| entry.ok())
207 .filter(filter_supported_files)
208 .map(|entry| entry.path())
209 .collect()
210}
211
212fn process_serde<I>(in_bytes: &Vec<u8>, input: I, format: OutFormat) -> Result<Vec<u8>>
213where
214 I: AsRef<Path>,
215{
216 let input = input.as_ref();
217 let mut string = String::new();
218
219 let mut classes = {
221 #[cfg(not(feature = "extra_fmt"))]
222 {
223 crate::serde::de::deserialize(in_bytes, &mut string, input)?
224 }
225 #[cfg(feature = "extra_fmt")]
226 {
227 crate::serde_extra::de::deserialize(in_bytes, &mut string, input)?
228 }
229 };
230
231 let out_bytes = match format {
233 OutFormat::Amd64 | OutFormat::Win32 | OutFormat::Xml => {
234 crate::serde::ser::to_bytes(input, format, &mut classes)?
235 }
236 #[cfg(feature = "extra_fmt")]
237 OutFormat::Json | OutFormat::Toml | OutFormat::Yaml => {
238 let mut classes = crate::types_wrapper::ClassPtrMap::from_class_map(classes);
239 crate::serde_extra::ser::to_bytes(input, format, &mut classes)?
240 }
241 };
242
243 Ok(out_bytes)
244}