use std::fmt;
#[derive(Clone, Copy, Debug)]
pub struct CompileLimits {
pub source_bytes: usize,
pub module_bytes: usize,
}
#[derive(Debug)]
pub enum CompileError {
SourceLimit {
actual: usize,
limit: usize,
},
ModuleLimit {
actual: usize,
limit: usize,
},
Invalid {
diagnostic: String,
},
UnsupportedEncoding,
}
impl fmt::Display for CompileError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::SourceLimit { actual, limit } => {
write!(formatter, "WAT source has {actual} bytes, limit {limit}")
}
Self::ModuleLimit { actual, limit } => {
write!(formatter, "compiled Wasm has {actual} bytes, limit {limit}")
}
Self::Invalid { diagnostic } => write!(formatter, "invalid WAT: {diagnostic}"),
Self::UnsupportedEncoding => formatter.write_str("expected a core Wasm module"),
}
}
}
impl std::error::Error for CompileError {}
pub fn compile(source: &str, limits: CompileLimits) -> Result<Vec<u8>, CompileError> {
if source.len() > limits.source_bytes {
return Err(CompileError::SourceLimit {
actual: source.len(),
limit: limits.source_bytes,
});
}
let module = wat::parse_str(source).map_err(|source| CompileError::Invalid {
diagnostic: source.to_string(),
})?;
if module.len() > limits.module_bytes {
return Err(CompileError::ModuleLimit {
actual: module.len(),
limit: limits.module_bytes,
});
}
if !module.starts_with(b"\0asm\x01\0\0\0") {
return Err(CompileError::UnsupportedEncoding);
}
Ok(module)
}
#[cfg(test)]
mod tests;