easy_archive/
ty.rs

1pub use strum::IntoEnumIterator;
2use strum_macros::EnumIter;
3
4use crate::archive::{
5    tar::{Tar, TarBz, TarGz, TarXz, TarZstd},
6    zip::Zip,
7};
8
9#[cfg_attr(feature = "wasm", wasm_bindgen::prelude::wasm_bindgen)]
10#[derive(EnumIter, Debug, Clone, Copy, PartialEq)]
11pub enum Fmt {
12    Tar,
13    TarGz,
14    TarXz,
15    TarBz,
16    TarZstd,
17    Zip,
18}
19
20impl Fmt {
21    pub fn decode(&self, buffer: Vec<u8>) -> Option<Vec<File>> {
22        match self {
23            Fmt::Zip => Zip::decode(buffer),
24            Fmt::Tar => Tar::decode(buffer),
25            Fmt::TarGz => TarGz::decode(buffer),
26            Fmt::TarXz => TarXz::decode(buffer),
27            Fmt::TarBz => TarBz::decode(buffer),
28            Fmt::TarZstd => TarZstd::decode(buffer),
29        }
30    }
31    pub fn encode(&self, files: Vec<File>) -> Option<Vec<u8>> {
32        match self {
33            Fmt::Zip => Zip::encode(files),
34            Fmt::Tar => Tar::encode(files),
35            Fmt::TarGz => TarGz::encode(files),
36            Fmt::TarXz => TarXz::encode(files),
37            Fmt::TarBz => TarBz::encode(files),
38            Fmt::TarZstd => TarZstd::encode(files),
39        }
40    }
41
42    pub fn guess(name: &str) -> Option<Self> {
43        for fmt in Fmt::iter() {
44            for ext in fmt.extensions() {
45                if name.ends_with(ext) {
46                    return Some(fmt);
47                }
48            }
49        }
50        None
51    }
52
53    pub fn extensions(&self) -> &[&'static str] {
54        match self {
55            Fmt::Tar => &[".tar"],
56            Fmt::TarGz => &[".tar.gz", ".tgz"],
57            Fmt::TarXz => &[".tar.xz", ".txz"],
58            Fmt::TarBz => &[".tar.bz2", ".tbz2"],
59            Fmt::TarZstd => &[".tzstd", ".tzst", ".tar.zst"],
60            Fmt::Zip => &[".zip"],
61        }
62    }
63}
64
65#[cfg_attr(feature = "wasm", wasm_bindgen::prelude::wasm_bindgen)]
66#[derive(Debug, Clone, Default)]
67pub struct File {
68    #[cfg_attr(feature = "wasm", wasm_bindgen(skip))]
69    pub buffer: Vec<u8>,
70    #[cfg_attr(feature = "wasm", wasm_bindgen(skip))]
71    pub path: String,
72    pub mode: Option<u32>,
73    #[cfg_attr(feature = "wasm", wasm_bindgen(js_name = "isDir"))]
74    pub is_dir: bool,
75    #[cfg_attr(feature = "wasm", wasm_bindgen(js_name = "lastModified"))]
76    pub last_modified: Option<u64>,
77}
78
79#[cfg(feature = "wasm")]
80use wasm_bindgen::prelude::*;
81
82#[cfg_attr(feature = "wasm", wasm_bindgen::prelude::wasm_bindgen)]
83impl File {
84    #[cfg_attr(feature = "wasm", wasm_bindgen(constructor))]
85    pub fn new(
86        path: String,
87        buffer: Vec<u8>,
88        mode: Option<u32>,
89        is_dir: bool,
90        last_modified: Option<u64>,
91    ) -> Self {
92        File {
93            path,
94            buffer,
95            mode,
96            is_dir,
97            last_modified,
98        }
99    }
100}
101
102#[cfg(feature = "wasm")]
103#[wasm_bindgen]
104impl File {
105    // To reduce memory consumption
106    // get buffer should be placed last
107    #[wasm_bindgen(getter = buffer)]
108    pub fn get_buffer(self) -> Vec<u8> {
109        self.buffer
110    }
111    #[wasm_bindgen(setter = buffer)]
112    pub fn set_buffer(&mut self, buffer: Vec<u8>) {
113        self.buffer = buffer;
114    }
115
116    #[wasm_bindgen(getter = path)]
117    pub fn get_path(&self) -> String {
118        self.path.clone()
119    }
120
121    #[wasm_bindgen(setter = path)]
122    pub fn set_path(&mut self, path: String) {
123        self.path = path;
124    }
125
126    #[wasm_bindgen(getter = bufferSize)]
127    pub fn buffer_size(&self) -> usize {
128        self.buffer.len()
129    }
130    #[wasm_bindgen]
131    pub fn clone(&self) -> Self {
132        Clone::clone(self)
133    }
134}
135
136pub trait Encode {
137    fn encode(files: Vec<File>) -> Option<Vec<u8>>;
138}
139
140pub trait Decode {
141    fn decode<T: AsRef<[u8]>>(buffer: T) -> Option<Vec<File>>;
142}
143
144pub trait Archive: Encode + Decode {}
145
146#[cfg(test)]
147mod test {
148    use super::Fmt;
149
150    #[test]
151    fn test_guess() {
152        for (name, fmt) in [
153            ("a.zip", Fmt::Zip),
154            ("a.tar", Fmt::Tar),
155            ("a.tar.gz", Fmt::TarGz),
156            ("a.tar.xz", Fmt::TarXz),
157            ("a.tar.bz2", Fmt::TarBz),
158        ] {
159            assert!(Fmt::guess(name) == Some(fmt))
160        }
161    }
162}