i_slint_compiler/
fileaccess.rs1use std::borrow::Cow;
5use std::fs;
6
7#[derive(Clone)]
8pub struct VirtualFile {
9 pub canon_path: std::path::PathBuf,
10 pub builtin_contents: Option<&'static [u8]>,
11}
12
13impl VirtualFile {
14 pub fn read(&self) -> Cow<'static, [u8]> {
15 match self.builtin_contents {
16 Some(static_data) => Cow::Borrowed(static_data),
17 None => Cow::Owned(std::fs::read(&self.canon_path).unwrap()),
18 }
19 }
20
21 pub fn is_builtin(&self) -> bool {
22 self.builtin_contents.is_some()
23 }
24}
25
26pub fn styles() -> Vec<&'static str> {
27 builtin_library::styles()
28}
29
30pub fn load_file(path: &std::path::Path) -> Option<VirtualFile> {
31 match path.strip_prefix("builtin:/") {
32 Ok(builtin_path) => builtin_library::load_builtin_file(builtin_path),
33 Err(_) => path.exists().then(|| {
34 let path =
35 crate::pathutils::join(&std::env::current_dir().ok().unwrap_or_default(), path)
36 .unwrap_or_else(|| path.to_path_buf());
37 VirtualFile { canon_path: crate::pathutils::clean_path(&path), builtin_contents: None }
38 }),
39 }
40}
41
42#[test]
43fn test_load_file() {
44 let builtin = load_file(&std::path::PathBuf::from(
45 "builtin:/foo/../common/./MadeWithSlint-logo-dark.svg",
46 ))
47 .unwrap();
48 assert!(builtin.is_builtin());
49 assert_eq!(
50 builtin.canon_path,
51 std::path::PathBuf::from("builtin:/common/MadeWithSlint-logo-dark.svg")
52 );
53
54 let dir = std::env::var_os("CARGO_MANIFEST_DIR").unwrap().to_string_lossy().to_string();
55 let dir_path = std::path::PathBuf::from(dir);
56
57 let non_existing = dir_path.join("XXXCargo.tomlXXX");
58 assert!(load_file(&non_existing).is_none());
59
60 assert!(dir_path.exists()); let cargo_toml = dir_path.join("Cargo.toml");
63 let abs_cargo_toml = load_file(&cargo_toml).unwrap();
64 assert!(!abs_cargo_toml.is_builtin());
65 assert!(crate::pathutils::is_absolute(&abs_cargo_toml.canon_path));
66 assert!(abs_cargo_toml.canon_path.exists());
67
68 let current = std::env::current_dir().unwrap();
69 assert!(current.ends_with("compiler")); let cargo_toml = std::path::PathBuf::from("./tests/../Cargo.toml");
72 let rel_cargo_toml = load_file(&cargo_toml).unwrap();
73 assert!(!rel_cargo_toml.is_builtin());
74 assert!(crate::pathutils::is_absolute(&rel_cargo_toml.canon_path));
75 assert!(rel_cargo_toml.canon_path.exists());
76
77 assert_eq!(abs_cargo_toml.canon_path, rel_cargo_toml.canon_path);
78}
79
80pub fn write_file_if_changed(path: &std::path::Path, content: &[u8]) -> std::io::Result<()> {
88 if fs::read(path).is_ok_and(|existing| existing == content) {
89 return Ok(());
90 }
91 fs::write(path, content)
92}
93
94mod builtin_library {
95 include!(env!("SLINT_WIDGETS_LIBRARY"));
96
97 pub type BuiltinDirectory<'a> = [&'a BuiltinFile<'a>];
98
99 pub struct BuiltinFile<'a> {
100 pub path: &'a str,
101 pub contents: &'static [u8],
102 }
103
104 use super::VirtualFile;
105
106 const ALIASES: &[(&str, &str)] = &[
107 ("cosmic-light", "cosmic"),
108 ("cosmic-dark", "cosmic"),
109 ("fluent-light", "fluent"),
110 ("fluent-dark", "fluent"),
111 ("material-light", "material"),
112 ("material-dark", "material"),
113 ("cupertino-light", "cupertino"),
114 ("cupertino-dark", "cupertino"),
115 ];
116
117 pub(crate) fn styles() -> Vec<&'static str> {
118 widget_library()
119 .iter()
120 .filter_map(|(style, directory)| {
121 if directory.iter().any(|f| f.path == "std-widgets.slint") {
122 Some(*style)
123 } else {
124 None
125 }
126 })
127 .chain(ALIASES.iter().map(|x| x.0))
128 .collect()
129 }
130
131 pub(crate) fn load_builtin_file(builtin_path: &std::path::Path) -> Option<VirtualFile> {
132 let mut components = Vec::new();
133 for part in builtin_path.iter() {
134 if part == ".." {
135 components.pop();
136 } else if part != "." {
137 components.push(part);
138 }
139 }
140 if let Some(f) = components.first_mut()
141 && let Some((_, x)) = ALIASES.iter().find(|x| x.0 == *f)
142 {
143 *f = std::ffi::OsStr::new(x);
144 }
145 if let &[folder, file] = components.as_slice() {
146 let library = widget_library().iter().find(|x| x.0 == folder)?.1;
147 library.iter().find_map(|builtin_file| {
148 if builtin_file.path == file {
149 Some(VirtualFile {
150 canon_path: std::path::PathBuf::from(format!(
151 "builtin:/{}/{}",
152 folder.to_str().unwrap(),
153 builtin_file.path
154 )),
155 builtin_contents: Some(builtin_file.contents),
156 })
157 } else {
158 None
159 }
160 })
161 } else {
162 None
163 }
164 }
165}