tinywasm_types/
archive.rs1use core::fmt::{Display, Formatter};
2
3use alloc::vec::Vec;
4
5use crate::Module;
6
7#[rustfmt::skip]
8const TWASM_MAGIC: [u8; 16] = [ TWASM_MAGIC_PREFIX[0], TWASM_MAGIC_PREFIX[1], TWASM_MAGIC_PREFIX[2], TWASM_MAGIC_PREFIX[3], TWASM_VERSION[0], TWASM_VERSION[1], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
9const TWASM_MAGIC_PREFIX: &[u8; 4] = b"TWAS";
10const TWASM_VERSION: &[u8; 2] = b"03";
11
12fn validate_magic(wasm: &[u8]) -> Result<usize, TwasmError> {
13 if wasm.len() < TWASM_MAGIC.len() || &wasm[..TWASM_MAGIC_PREFIX.len()] != TWASM_MAGIC_PREFIX {
14 return Err(TwasmError::InvalidMagic);
15 }
16 if &wasm[TWASM_MAGIC_PREFIX.len()..TWASM_MAGIC_PREFIX.len() + TWASM_VERSION.len()] != TWASM_VERSION {
17 return Err(TwasmError::InvalidVersion);
18 }
19 if wasm[TWASM_MAGIC_PREFIX.len() + TWASM_VERSION.len()..TWASM_MAGIC.len()] != [0; 10] {
20 return Err(TwasmError::InvalidPadding);
21 }
22
23 Ok(TWASM_MAGIC.len())
24}
25
26#[derive(Debug)]
27pub enum TwasmError {
28 InvalidMagic,
29 InvalidVersion,
30 InvalidPadding,
31 InvalidArchive(postcard::Error),
32}
33
34impl Display for TwasmError {
35 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
36 match self {
37 Self::InvalidMagic => write!(f, "Invalid twasm: invalid magic number"),
38 Self::InvalidVersion => write!(f, "Invalid twasm: invalid version"),
39 Self::InvalidPadding => write!(f, "Invalid twasm: invalid padding"),
40 Self::InvalidArchive(e) => write!(f, "Invalid twasm: {e}"),
41 }
42 }
43}
44
45#[cfg(feature = "std")]
46extern crate std;
47
48impl core::error::Error for TwasmError {}
49
50impl Module {
51 pub fn try_from_twasm(wasm: &[u8]) -> Result<Self, TwasmError> {
53 let len = validate_magic(wasm)?;
54 postcard::from_bytes(&wasm[len..]).map_err(TwasmError::InvalidArchive)
55 }
56
57 pub fn serialize_twasm(&self) -> Result<Vec<u8>, TwasmError> {
59 let buf = Vec::from(TWASM_MAGIC);
60 postcard::to_extend(self, buf).map_err(TwasmError::InvalidArchive)
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67
68 #[test]
69 fn test_invalid_magic() {
70 let wasm = Module::default();
71 let mut twasm = wasm.serialize_twasm().expect("should serialize");
72 twasm[0] = 0;
73 assert!(matches!(Module::try_from_twasm(&twasm), Err(TwasmError::InvalidMagic)));
74 }
75
76 #[test]
77 fn test_invalid_version() {
78 let wasm = Module::default();
79 let mut twasm = wasm.serialize_twasm().expect("should serialize");
80 twasm[4] = 0;
81 assert!(matches!(Module::try_from_twasm(&twasm), Err(TwasmError::InvalidVersion)));
82 }
83}