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