wasmer_pack/
files.rs

1use std::{
2    collections::BTreeMap,
3    fmt::{self, Debug, Formatter},
4    ops::Index,
5    path::{Path, PathBuf},
6};
7
8use anyhow::{Context, Error};
9
10/// A set of files loaded into memory.
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct Files {
13    members: BTreeMap<PathBuf, SourceFile>,
14}
15
16impl Files {
17    pub fn new() -> Self {
18        Files {
19            members: BTreeMap::new(),
20        }
21    }
22
23    pub fn insert(&mut self, path: impl Into<PathBuf>, file: SourceFile) {
24        self.members.insert(path.into(), file);
25    }
26
27    pub fn insert_child_directory(&mut self, dir: impl AsRef<Path>, files: Files) {
28        let dir = dir.as_ref();
29
30        for (path, file) in files {
31            let path = dir.join(path);
32            self.insert(path, file);
33        }
34    }
35
36    pub fn iter(&self) -> impl Iterator<Item = (&Path, &SourceFile)> + '_ {
37        self.members.iter().map(|(k, v)| (k.as_path(), v))
38    }
39
40    pub fn save_to_disk(&self, output_dir: impl AsRef<Path>) -> Result<(), Error> {
41        let output_dir = output_dir.as_ref();
42
43        for (path, file) in self.iter() {
44            let path = output_dir.join(path);
45
46            if let Some(parent) = path.parent() {
47                std::fs::create_dir_all(parent).with_context(|| {
48                    format!("Unable to create the \"{}\" directory", parent.display())
49                })?;
50            }
51
52            std::fs::write(&path, file.contents())
53                .with_context(|| format!("Unable to save to \"{}\"", path.display()))?;
54        }
55
56        Ok(())
57    }
58
59    pub fn get_mut(&mut self, path: impl AsRef<Path>) -> Option<&mut SourceFile> {
60        self.members.get_mut(path.as_ref())
61    }
62}
63
64impl Default for Files {
65    fn default() -> Self {
66        Files::new()
67    }
68}
69
70impl IntoIterator for Files {
71    type Item = (PathBuf, SourceFile);
72
73    type IntoIter = <BTreeMap<PathBuf, SourceFile> as IntoIterator>::IntoIter;
74
75    fn into_iter(self) -> Self::IntoIter {
76        self.members.into_iter()
77    }
78}
79
80impl Extend<(PathBuf, SourceFile)> for Files {
81    fn extend<T: IntoIterator<Item = (PathBuf, SourceFile)>>(&mut self, iter: T) {
82        for (path, file) in iter {
83            self.insert(path, file);
84        }
85    }
86}
87
88impl From<wai_bindgen_gen_core::Files> for Files {
89    fn from(files: wai_bindgen_gen_core::Files) -> Self {
90        let mut f = Files::new();
91
92        for (path, contents) in files.iter() {
93            f.insert(path, contents.into());
94        }
95
96        f
97    }
98}
99
100impl<P: AsRef<Path>> Index<P> for Files {
101    type Output = SourceFile;
102
103    #[track_caller]
104    fn index(&self, index: P) -> &Self::Output {
105        let index = index.as_ref();
106
107        match self.members.get(index) {
108            Some(file) => file,
109            None => panic!("No such file, \"{}\"", index.display()),
110        }
111    }
112}
113
114/// A file in memory.
115#[derive(Clone, Default, PartialEq, Eq)]
116pub struct SourceFile(pub Vec<u8>);
117
118impl SourceFile {
119    pub fn empty() -> Self {
120        SourceFile(Vec::new())
121    }
122
123    pub fn new(contents: Vec<u8>) -> Self {
124        SourceFile(contents)
125    }
126
127    pub fn contents(&self) -> &[u8] {
128        &self.0
129    }
130
131    pub fn utf8_contents(&self) -> Option<&str> {
132        std::str::from_utf8(&self.0).ok()
133    }
134}
135
136impl From<&str> for SourceFile {
137    fn from(s: &str) -> Self {
138        SourceFile::from(s.to_string())
139    }
140}
141
142impl From<String> for SourceFile {
143    fn from(s: String) -> Self {
144        SourceFile::new(s.into_bytes())
145    }
146}
147
148impl From<&[u8]> for SourceFile {
149    fn from(v: &[u8]) -> Self {
150        SourceFile::from(v.to_vec())
151    }
152}
153
154impl From<&Vec<u8>> for SourceFile {
155    fn from(v: &Vec<u8>) -> Self {
156        SourceFile::from(v.clone())
157    }
158}
159
160impl From<Vec<u8>> for SourceFile {
161    fn from(v: Vec<u8>) -> Self {
162        SourceFile::new(v)
163    }
164}
165
166impl Debug for SourceFile {
167    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
168        let SourceFile(contents) = self;
169
170        f.debug_tuple("SourceFile")
171            .field(
172                self.utf8_contents()
173                    .as_ref()
174                    .map(|c| c as &dyn Debug)
175                    .unwrap_or(contents),
176            )
177            .finish()
178    }
179}