wasmhaiku_glue/
fileparts.rs

1#[derive(Debug)]
2pub struct FilePart {
3	pub file_name: String,
4	pub mime_str: String,
5	pub bytes: Vec<u8>,
6}
7
8#[derive(Debug)]
9pub struct FileParts {
10	pub inner: Vec<FilePart>,
11}
12
13impl From<Vec<u8>> for FileParts {
14	fn from(raw: Vec<u8>) -> FileParts {
15		if raw.len() < 16 {
16			return FileParts { inner: vec![] };
17		}
18
19		let total_len = i32::from_le_bytes((&raw[0..4]).try_into().unwrap()) as usize;
20		let mut v = Vec::<FilePart>::with_capacity(total_len);
21		let mut v_offset = (1 + (total_len * 3)) * 4;
22		for i in 0..total_len {
23			let offset = (1 + (i * 3)) * 4;
24			let file_name_len =
25				i32::from_le_bytes((&raw[offset..offset + 4]).try_into().unwrap()) as usize;
26			let file_name = String::from_utf8((&raw[v_offset..v_offset + file_name_len]).to_vec())
27				.unwrap_or_default();
28			v_offset += file_name_len;
29
30			let mime_str_len =
31				i32::from_le_bytes((&raw[offset + 4..offset + 8]).try_into().unwrap()) as usize;
32			let mime_str = String::from_utf8((&raw[v_offset..v_offset + mime_str_len]).to_vec())
33				.unwrap_or_default();
34			v_offset += mime_str_len;
35
36			let bytes_len =
37				i32::from_le_bytes((&raw[offset + 8..offset + 12]).try_into().unwrap()) as usize;
38			let bytes = (&raw[v_offset..v_offset + bytes_len]).to_vec();
39			v_offset += bytes_len;
40
41			v.push(FilePart {
42				file_name,
43				mime_str,
44				bytes,
45			});
46		}
47
48		FileParts { inner: v }
49	}
50}
51
52impl FileParts {
53	pub fn to_vec(&self) -> Vec<u8> {
54		let mut nv = vec![0 as u8; (1 + (3 * self.inner.len())) * 4];
55		nv.splice(0..4, (self.inner.len() as i32).to_le_bytes());
56		self.inner
57			.iter()
58			.enumerate()
59			.fold(nv, |mut accum, (index, item)| {
60				let file_name = item.file_name.as_bytes();
61				accum.extend(file_name);
62				let mime_str = item.mime_str.as_bytes();
63				accum.extend(mime_str);
64				accum.extend(&item.bytes);
65				let offset = (1 + (index * 3)) * 4;
66				accum.splice(offset..offset + 4, (file_name.len() as i32).to_le_bytes());
67				accum.splice(
68					offset + 4..offset + 8,
69					(mime_str.len() as i32).to_le_bytes(),
70				);
71				accum.splice(
72					offset + 8..offset + 12,
73					(item.bytes.len() as i32).to_le_bytes(),
74				);
75				accum
76			})
77	}
78}
79
80#[cfg(test)]
81mod tests {
82	use super::*;
83
84	#[test]
85	fn from_into() {
86		let fp = FileParts {
87			inner: vec![
88				FilePart {
89					file_name: String::from("a.txt"),
90					mime_str: String::from("text/plain"),
91					bytes: b"123".to_vec(),
92				},
93				FilePart {
94					file_name: String::from("g.jpg"),
95					mime_str: String::from("image/jpeg"),
96					bytes: b"!@#$%^&*()".to_vec(),
97				},
98			],
99		};
100
101		let v = fp.to_vec();
102		println!("{:?}", v);
103
104		let fp2: FileParts = v.into();
105		println!("{:?}", fp2);
106
107		assert_eq!(fp.inner[0].file_name, fp2.inner[0].file_name);
108		assert_eq!(fp.inner[1].bytes, fp2.inner[1].bytes);
109	}
110}