summaryrefslogtreecommitdiff
path: root/src/embedded.rs
blob: 8f6c14e7d3e07f2fa7385be271138cd21ccbd5fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use std::{
    fs::{create_dir, File, OpenOptions},
    io::{self, Write},
    path::Path,
};

pub static EMBEDDED_FILES: EmbeddedFiles = rustlings_macros::include_files!();

#[derive(Clone, Copy)]
pub enum WriteStrategy {
    IfNotExists,
    Overwrite,
}

impl WriteStrategy {
    fn open<P: AsRef<Path>>(self, path: P) -> io::Result<File> {
        match self {
            Self::IfNotExists => OpenOptions::new().create_new(true).write(true).open(path),
            Self::Overwrite => OpenOptions::new()
                .create(true)
                .write(true)
                .truncate(true)
                .open(path),
        }
    }
}

struct EmbeddedFile {
    path: &'static str,
    content: &'static [u8],
}

impl EmbeddedFile {
    fn write_to_disk(&self, strategy: WriteStrategy) -> io::Result<()> {
        strategy.open(self.path)?.write_all(self.content)
    }
}

struct EmbeddedFlatDir {
    path: &'static str,
    readme: EmbeddedFile,
    content: &'static [EmbeddedFile],
}

impl EmbeddedFlatDir {
    fn init_on_disk(&self) -> io::Result<()> {
        let path = Path::new(self.path);

        if let Err(e) = create_dir(path) {
            if !path.is_dir() {
                return Err(e);
            }
        }

        self.readme.write_to_disk(WriteStrategy::Overwrite)
    }
}

struct ExercisesDir {
    readme: EmbeddedFile,
    files: &'static [EmbeddedFile],
    dirs: &'static [EmbeddedFlatDir],
}

pub struct EmbeddedFiles {
    info_toml_content: &'static str,
    exercises_dir: ExercisesDir,
}

impl EmbeddedFiles {
    pub fn init_exercises_dir(&self) -> io::Result<()> {
        create_dir("exercises")?;
        self.exercises_dir
            .readme
            .write_to_disk(WriteStrategy::Overwrite)
    }

    pub fn write_exercise_to_disk(&self, path: &Path, strategy: WriteStrategy) -> io::Result<()> {
        if let Some(file) = self
            .exercises_dir
            .files
            .iter()
            .find(|file| file.path == path.as_os_str())
        {
            return file.write_to_disk(strategy);
        }

        for dir in self.exercises_dir.dirs {
            if let Some(file) = dir
                .content
                .iter()
                .find(|file| file.path == path.as_os_str())
            {
                dir.init_on_disk()?;
                return file.write_to_disk(strategy);
            }
        }

        Err(io::Error::from(io::ErrorKind::NotFound))
    }
}