scx_raw_pmu/
resources.rs

1use include_dir::{include_dir, Dir};
2use std::borrow::Cow;
3use std::fs;
4use std::io;
5use std::path::PathBuf;
6
7static ARCH_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/arch");
8
9#[derive(Debug)]
10pub(crate) enum ResourceDir {
11    Embedded(&'static Dir<'static>),
12    Filesystem(PathBuf),
13}
14
15impl Default for ResourceDir {
16    fn default() -> Self {
17        ResourceDir::Embedded(&ARCH_DIR)
18    }
19}
20
21#[derive(Debug)]
22pub(crate) enum ResourceFile {
23    Embedded(&'static include_dir::File<'static>),
24    Filesystem { name: String, full_path: PathBuf },
25}
26
27impl ResourceFile {
28    pub fn path(&self) -> &str {
29        match self {
30            ResourceFile::Embedded(file) => file.path().to_str().unwrap(),
31            ResourceFile::Filesystem { name, .. } => name,
32        }
33    }
34
35    pub fn read(&self) -> io::Result<Cow<'static, [u8]>> {
36        match self {
37            ResourceFile::Embedded(file) => Ok(Cow::Borrowed(file.contents())),
38            ResourceFile::Filesystem { full_path, .. } => {
39                let contents = fs::read(full_path)?;
40                Ok(Cow::Owned(contents))
41            }
42        }
43    }
44}
45
46impl ResourceDir {
47    pub(crate) fn new_filesystem(path: PathBuf) -> Self {
48        ResourceDir::Filesystem(path)
49    }
50
51    pub(crate) fn get_file(&self, path: &str) -> io::Result<ResourceFile> {
52        match self {
53            ResourceDir::Embedded(dir) => {
54                let full_path = dir.path().join(path);
55                let file = ARCH_DIR
56                    .get_file(full_path.to_str().unwrap())
57                    .ok_or_else(|| {
58                        io::Error::new(
59                            io::ErrorKind::NotFound,
60                            "file not found in embedded resources",
61                        )
62                    })?;
63                Ok(ResourceFile::Embedded(file))
64            }
65            ResourceDir::Filesystem(base_path) => {
66                let full_path = base_path.join(path);
67                if full_path.is_file() {
68                    let name = path.to_string();
69                    Ok(ResourceFile::Filesystem { name, full_path })
70                } else {
71                    Err(io::Error::new(
72                        io::ErrorKind::NotFound,
73                        format!("file not found: {}", full_path.display()),
74                    ))
75                }
76            }
77        }
78    }
79
80    pub(crate) fn get_dir(&self, path: &str) -> io::Result<ResourceDir> {
81        match self {
82            ResourceDir::Embedded(dir) => {
83                let full_path = dir.path().join(path);
84                let subdir = ARCH_DIR
85                    .get_dir(full_path.to_str().unwrap())
86                    .ok_or_else(|| {
87                        io::Error::new(
88                            io::ErrorKind::NotFound,
89                            "directory not found in embedded resources",
90                        )
91                    })?;
92                Ok(ResourceDir::Embedded(subdir))
93            }
94            ResourceDir::Filesystem(base_path) => {
95                let full_path = base_path.join(path);
96                if full_path.is_dir() {
97                    Ok(ResourceDir::Filesystem(full_path))
98                } else {
99                    Err(io::Error::new(
100                        io::ErrorKind::NotFound,
101                        format!("directory not found: {}", full_path.display()),
102                    ))
103                }
104            }
105        }
106    }
107
108    pub(crate) fn files(&self) -> io::Result<Vec<ResourceFile>> {
109        match self {
110            ResourceDir::Embedded(dir) => {
111                let mut files = Vec::new();
112                for file in dir.files() {
113                    files.push(ResourceFile::Embedded(file));
114                }
115                Ok(files)
116            }
117            ResourceDir::Filesystem(base_path) => {
118                let mut files = Vec::new();
119                for entry in fs::read_dir(base_path)? {
120                    let entry = entry?;
121                    let path = entry.path();
122                    if path.is_file() {
123                        let name = path.file_name().unwrap().to_str().unwrap().to_string();
124                        files.push(ResourceFile::Filesystem {
125                            name,
126                            full_path: path,
127                        });
128                    }
129                }
130                Ok(files)
131            }
132        }
133    }
134}
135
136#[cfg(test)]
137pub(crate) fn extract_arch_resources(path: &std::path::Path) -> Result<(), std::io::Error> {
138    ARCH_DIR.extract(path)
139}