1use std::{
7 io,
8 path::{Path, PathBuf},
9};
10
11#[derive(Debug, Clone)]
13pub struct QResourceFile {
14 alias: Option<String>,
15 path: PathBuf,
18}
19
20impl<T: AsRef<Path>> From<T> for QResourceFile {
21 fn from(value: T) -> Self {
22 Self::new(value)
23 }
24}
25
26impl QResourceFile {
27 pub fn new(path: impl AsRef<Path>) -> Self {
29 Self {
30 alias: None,
31 path: path.as_ref().to_path_buf(),
32 }
33 }
34
35 pub fn alias(mut self, alias: impl Into<String>) -> Self {
37 self.alias = Some(alias.into());
38 self
39 }
40
41 pub fn get_path(&self) -> &Path {
43 &self.path
44 }
45
46 fn write(self, writer: &mut impl io::Write) -> io::Result<()> {
47 let alias = self
48 .alias
49 .unwrap_or_else(|| self.path.to_string_lossy().to_string());
50 let alias = alias.escape_default();
51 #[cfg(test)]
52 let path = &self.path;
53 #[cfg(not(test))]
54 let path = std::fs::canonicalize(self.path)?;
55 writeln!(
56 writer,
57 " <file alias=\"{alias}\">{path}</file>",
58 path = path.display()
59 )
60 }
61}
62
63#[derive(Debug, Clone)]
65pub struct QResource {
66 language: Option<String>,
67 prefix: Option<String>,
68 files: Vec<QResourceFile>,
69}
70
71impl Default for QResource {
72 fn default() -> Self {
73 Self::new()
74 }
75}
76
77impl<T: Into<QResourceFile>> From<T> for QResource {
78 fn from(value: T) -> Self {
79 Self::new().file(value)
80 }
81}
82
83impl QResource {
84 pub fn new() -> Self {
86 Self {
87 language: None,
88 prefix: None,
89 files: vec![],
90 }
91 }
92
93 pub fn file<T: Into<QResourceFile>>(mut self, file: T) -> Self {
95 self.files.push(file.into());
96 self
97 }
98
99 pub fn files<T: Into<QResourceFile>>(mut self, files: impl IntoIterator<Item = T>) -> Self {
101 for file in files.into_iter() {
102 self.files.push(file.into());
103 }
104 self
105 }
106
107 pub fn get_files(&self) -> impl Iterator<Item = &QResourceFile> {
109 self.files.iter()
110 }
111
112 pub fn language(mut self, language: impl Into<String>) -> Self {
114 self.language = Some(language.into());
115 self
116 }
117
118 pub fn prefix(mut self, prefix: impl Into<String>) -> Self {
120 self.prefix = Some(prefix.into());
121 self
122 }
123
124 pub fn get_prefix(&self) -> Option<&str> {
126 self.prefix.as_deref()
127 }
128
129 fn write(self, writer: &mut impl io::Write) -> io::Result<()> {
130 let language = self
131 .language
132 .map(|language| format!(" language=\"{}\"", language.escape_default()))
133 .unwrap_or_default();
134 let prefix = self
135 .prefix
136 .map(|prefix| format!(" prefix=\"{}\"", prefix.escape_default()))
137 .unwrap_or_default();
138
139 writeln!(writer, " <qresource{language}{prefix}>")?;
140 for file in self.files.into_iter() {
141 file.write(writer)?;
142 }
143 writeln!(writer, " </qresource>")
144 }
145}
146
147#[derive(Debug, Clone)]
149pub struct QResources {
150 resources: Vec<QResource>,
151}
152
153impl Default for QResources {
154 fn default() -> Self {
155 Self::new()
156 }
157}
158
159impl<T: IntoIterator<Item = impl Into<QResourceFile>>> From<T> for QResources {
160 fn from(value: T) -> Self {
161 Self::new().resource(QResource::new().files(value))
162 }
163}
164
165impl QResources {
166 pub fn new() -> Self {
168 Self { resources: vec![] }
169 }
170
171 pub fn resource<T: Into<QResource>>(mut self, resource: T) -> Self {
173 self.resources.push(resource.into());
174 self
175 }
176
177 pub fn resources<T: Into<QResource>>(mut self, resources: impl IntoIterator<Item = T>) -> Self {
179 for resource in resources.into_iter() {
180 self.resources.push(resource.into());
181 }
182 self
183 }
184
185 pub fn get_resources_mut(&mut self) -> impl Iterator<Item = &mut QResource> {
187 self.resources.iter_mut()
188 }
189
190 pub fn get_resources(&self) -> impl Iterator<Item = &QResource> {
192 self.resources.iter()
193 }
194
195 pub fn write(self, writer: &mut impl io::Write) -> io::Result<()> {
197 writeln!(writer, "<RCC>")?;
198 for resource in self.resources.into_iter() {
199 resource.write(writer)?;
200 }
201 writeln!(writer, "</RCC>")
202 }
203}
204
205#[cfg(test)]
206mod test {
207 use super::*;
208
209 #[test]
210 fn resource_file() {
211 let mut result = Vec::new();
212 QResourceFile::new("path")
213 .alias("alias")
214 .write(&mut result)
215 .unwrap();
216 assert_eq!(
217 String::from_utf8(result).unwrap(),
218 " <file alias=\"alias\">path</file>\n"
219 );
220 }
221
222 #[test]
223 fn resource() {
224 let mut result = Vec::new();
225 QResource::new()
226 .language("language")
227 .prefix("prefix")
228 .write(&mut result)
229 .unwrap();
230 assert_eq!(
231 String::from_utf8(result).unwrap(),
232 " <qresource language=\"language\" prefix=\"prefix\">\n </qresource>\n"
233 );
234 }
235
236 #[test]
237 fn resources() {
238 let mut result = Vec::new();
239 QResources::new()
240 .resources(["a", "b"])
241 .resource(
242 QResource::new()
243 .prefix("prefix")
244 .files(["c", "d"])
245 .file(QResourceFile::new("e").alias("alias")),
246 )
247 .write(&mut result)
248 .unwrap();
249 assert_eq!(
250 String::from_utf8(result).unwrap(),
251 "<RCC>
252 <qresource>
253 <file alias=\"a\">a</file>
254 </qresource>
255 <qresource>
256 <file alias=\"b\">b</file>
257 </qresource>
258 <qresource prefix=\"prefix\">
259 <file alias=\"c\">c</file>
260 <file alias=\"d\">d</file>
261 <file alias=\"alias\">e</file>
262 </qresource>
263</RCC>
264"
265 );
266 }
267
268 #[test]
269 fn resources_from_files() {
270 let mut result = Vec::new();
271 QResources::from(["a", "b"]).write(&mut result).unwrap();
272 assert_eq!(
273 String::from_utf8(result).unwrap(),
274 format!(
275 "<RCC>
276 <qresource>
277 <file alias=\"a\">a</file>
278 <file alias=\"b\">b</file>
279 </qresource>
280</RCC>
281",
282 )
283 );
284 }
285}