gwasm_dispatcher/
blob.rs

1use crate::error::Error;
2use crate::taskdef::{FromTaskArg, IntoTaskArg, TaskArg};
3use std::fs;
4/**
5 Binary Large Objects
6
7**/
8use std::io::{self, Read, Seek, Write};
9use std::path::{Path, PathBuf};
10
11pub struct Blob(PathBuf);
12pub struct Output(pub(crate) PathBuf);
13
14impl Blob {
15    pub fn from_output(output: Output) -> Self {
16        Blob(output.0)
17    }
18
19    pub fn open(&self) -> io::Result<impl Read + Seek> {
20        fs::OpenOptions::new().read(true).open(&self.0)
21    }
22}
23
24impl Output {
25    pub fn open(&self) -> io::Result<impl Write + Seek> {
26        fs::OpenOptions::new()
27            .create(true)
28            .truncate(true)
29            .write(true)
30            .open(&self.0)
31    }
32
33    #[inline]
34    pub fn into_blob(self) -> Blob {
35        Blob::from_output(self)
36    }
37
38    pub fn file(self, path: &Path) -> Result<Blob, Error> {
39        let mut inf = fs::OpenOptions::new().read(true).open(path)?;
40        let mut outf = self.open()?;
41
42        io::copy(&mut inf, &mut outf)?;
43        Ok(Blob::from_output(self))
44    }
45
46    pub fn bytes(self, data: impl AsRef<[u8]>) -> Result<Blob, Error> {
47        let data = data.as_ref();
48        self.open()?.write_all(data)?;
49        Ok(Blob::from_output(self))
50    }
51}
52
53impl IntoTaskArg for Blob {
54    fn into_arg(&self, base: &Path) -> Result<TaskArg, Error> {
55        let cpath = em_canonicalize(&self.0)?;
56        let path = cpath.strip_prefix(base)?;
57        path.to_str()
58            .ok_or_else(|| Error::invalid_path(&self.0))
59            .map(|v| TaskArg::Blob(v.replace("\\", "/")))
60    }
61}
62
63#[cfg(target_arch = "wasm32")]
64fn em_canonicalize(path: &Path) -> io::Result<PathBuf> {
65    use std::path::Component;
66
67    let mut out_path = PathBuf::new();
68
69    for c in path.components() {
70        match c {
71            Component::ParentDir => {
72                let _ = out_path.pop();
73            }
74            Component::Normal(v) => out_path.push(v),
75            Component::RootDir => out_path.push("/"),
76            _ => (),
77        }
78    }
79
80    Ok(out_path)
81}
82
83#[cfg(not(target_arch = "wasm32"))]
84fn em_canonicalize(path: &Path) -> io::Result<PathBuf> {
85    path.canonicalize()
86}
87
88impl FromTaskArg for Blob {
89    fn from_arg(arg: TaskArg, base: &Path) -> Result<Self, Error> {
90        match arg {
91            TaskArg::Blob(path) => Ok(Blob(base.join(path))),
92            _ => Err(Error::BlobExpected),
93        }
94    }
95}
96
97impl IntoTaskArg for Output {
98    fn into_arg(&self, base: &Path) -> Result<TaskArg, Error> {
99        let path = self.0.strip_prefix(base)?;
100        path.to_str()
101            .ok_or_else(|| Error::invalid_path(&self.0))
102            .map(|v| TaskArg::Output(v.into()))
103    }
104}
105
106impl FromTaskArg for Output {
107    fn from_arg(arg: TaskArg, base: &Path) -> Result<Self, Error> {
108        Ok(match arg {
109            TaskArg::Output(path) => Output(PathBuf::from(&base.join(path))),
110            _ => return Err(Error::OutputExpected),
111        })
112    }
113}