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 #[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]
127 pub fn clone(&self) -> Self {
128 Clone::clone(self)
129 }
130}
131
132pub trait Encode {
133 fn encode(_files: Vec<File>) -> Option<Vec<u8>> {
134 todo!()
135 }
136}
137
138pub trait Decode {
139 fn decode(buffer: Vec<u8>) -> Option<Vec<File>>;
140}
141
142pub trait Archive: Encode + Decode {}
143
144#[cfg(test)]
145mod test {
146 use super::Fmt;
147
148 #[test]
149 fn test_guess() {
150 for (name, fmt) in [
151 ("a.zip", Fmt::Zip),
152 ("a.tar", Fmt::Tar),
153 ("a.tar.gz", Fmt::TarGz),
154 ("a.tar.xz", Fmt::TarXz),
155 ("a.tar.bz2", Fmt::TarBz),
156 ] {
157 assert!(Fmt::guess(name) == Some(fmt))
158 }
159 }
160}