//! WASM bridge types and helpers for plugin communication use std::collections::HashMap; use serde::{Deserialize, Serialize}; /// Memory allocation info for passing data between host and plugin #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WasmMemoryAlloc { /// Pointer to allocated memory pub ptr: u32, /// Size of allocation in bytes pub len: u32, } /// Request from host to plugin #[derive(Debug, Clone, Serialize, Deserialize)] pub struct HostRequest { /// Request ID for matching with response pub request_id: String, /// Method name being called pub method: String, /// Serialized parameters pub params: Vec, } /// Response from plugin to host #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PluginResponse { /// Request ID this response corresponds to pub request_id: String, /// Success or error pub result: WasmResult>, } /// Result type for WASM operations #[derive(Debug, Clone, Serialize, Deserialize)] pub enum WasmResult { Ok(T), Err(String), } impl From> for WasmResult { fn from(r: Result) -> Self { match r { Ok(v) => WasmResult::Ok(v), Err(e) => WasmResult::Err(e), } } } /// Host functions available to plugins pub mod host_functions { /// Log a message from plugin pub const LOG: &str = "host_log"; /// Read a file (if permitted) pub const READ_FILE: &str = "host_read_file"; /// Write a file (if permitted) pub const WRITE_FILE: &str = "host_write_file"; /// Make an HTTP request (if permitted) pub const HTTP_REQUEST: &str = "host_http_request"; /// Get configuration value pub const GET_CONFIG: &str = "host_get_config"; /// Emit an event pub const EMIT_EVENT: &str = "host_emit_event"; } /// Log level for plugin logging #[derive(Debug, Clone, Copy, Serialize, Deserialize)] pub enum LogLevel { Trace, Debug, Info, Warn, Error, } /// Log message from plugin #[derive(Debug, Clone, Serialize, Deserialize)] pub struct LogMessage { pub level: LogLevel, pub target: String, pub message: String, pub fields: HashMap, } /// HTTP request parameters #[derive(Debug, Clone, Serialize, Deserialize)] pub struct HttpRequest { pub method: String, pub url: String, pub headers: HashMap, pub body: Option>, } /// HTTP response #[derive(Debug, Clone, Serialize, Deserialize)] pub struct HttpResponse { pub status: u16, pub headers: HashMap, pub body: Vec, } /// Helper functions for serializing/deserializing data across WASM boundary pub mod helpers { use super::*; /// Serialize a value to bytes for passing to WASM pub fn serialize(value: &T) -> Result, String> { serde_json::to_vec(value).map_err(|e| format!("Serialization error: {}", e)) } /// Deserialize bytes from WASM to a value pub fn deserialize Deserialize<'de>>( bytes: &[u8], ) -> Result { serde_json::from_slice(bytes) .map_err(|e| format!("Deserialization error: {}", e)) } /// Create a success response pub fn ok_response( request_id: String, value: &T, ) -> Result, String> { let result = WasmResult::Ok(serialize(value)?); let response = PluginResponse { request_id, result }; serialize(&response) } /// Create an error response pub fn error_response( request_id: String, error: String, ) -> Result, String> { let result = WasmResult::>::Err(error); let response = PluginResponse { request_id, result }; serialize(&response) } } #[cfg(test)] mod tests { use super::{helpers::*, *}; #[test] fn test_serialize_deserialize() { let data = vec![1u8, 2, 3, 4]; let bytes = serialize(&data).unwrap(); let recovered: Vec = deserialize(&bytes).unwrap(); assert_eq!(data, recovered); } #[test] fn test_ok_response() { let request_id = "test-123".to_string(); let value = "success"; let response_bytes = ok_response(request_id.clone(), &value).unwrap(); let response: PluginResponse = deserialize(&response_bytes).unwrap(); assert_eq!(response.request_id, request_id); match response.result { WasmResult::Ok(data) => { let recovered: String = deserialize(&data).unwrap(); assert_eq!(recovered, value); }, WasmResult::Err(_) => panic!("Expected Ok result"), } } #[test] fn test_error_response() { let request_id = "test-456".to_string(); let error_msg = "Something went wrong"; let response_bytes = error_response(request_id.clone(), error_msg.to_string()).unwrap(); let response: PluginResponse = deserialize(&response_bytes).unwrap(); assert_eq!(response.request_id, request_id); match response.result { WasmResult::Err(msg) => assert_eq!(msg, error_msg), WasmResult::Ok(_) => panic!("Expected Err result"), } } }