1use std::fs;
3use std::path::Path;
4
5use anyhow::{Context, Result};
6use include_dir::{Dir, DirEntry, include_dir};
7
8pub mod patches;
9
10const EXAMPLES_DIR: Dir = include_dir!("examples");
12
13pub fn get_example_names() -> impl Iterator<Item = &'static str> {
15 EXAMPLES_DIR.dirs().map(|dir| {
16 dir.path()
17 .as_os_str()
18 .to_str()
19 .expect("Invalid unicode in path")
20 })
21}
22
23pub struct Example(Dir<'static>);
25
26impl Example {
27 pub fn from_name(name: &str) -> Result<Self> {
29 let dir = EXAMPLES_DIR
30 .get_dir(name)
31 .with_context(|| format!("Example '{name}' not found"))?;
32
33 Ok(Self(dir.clone()))
34 }
35
36 pub fn get_readme(&self) -> Result<&'static str> {
38 self.0
39 .get_file(self.0.path().join("README.txt"))
40 .context("Missing file")?
41 .contents_utf8()
42 .context("File not UTF-8 encoded")
43 }
44
45 pub fn extract(&self, new_path: &Path) -> Result<()> {
49 fs::create_dir(new_path)?;
51 for entry in self.0.entries() {
52 match entry {
53 DirEntry::Dir(_) => panic!("Subdirectories in examples not supported"),
54 DirEntry::File(f) => {
55 let file_name = f.path().file_name().unwrap();
56 let file_path = new_path.join(file_name);
57 fs::write(&file_path, f.contents())?;
58 }
59 }
60 }
61
62 Ok(())
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn all_examples_have_readme() {
72 for example in get_example_names() {
73 let readme = Example::from_name(example)
74 .unwrap()
75 .get_readme()
76 .with_context(|| format!("Could not load readme for {example}"))
77 .unwrap();
78
79 assert!(!readme.trim().is_empty());
80 }
81 }
82}