http-wasm-guest 0.4.0

a library providing a http-wasm guest handler
Documentation
use std::{fmt::Display, ops::Deref, string::FromUtf8Error};

mod handler;

pub fn get_config() -> Result<String, FromUtf8Error> {
    String::from_utf8(handler::get_config())
}

/**
 * enables the specified Features on the host.
 *
 * https://http-wasm.io/http-handler-abi/#enable_features
 *
 */
pub fn enable_feature(feature: crate::Feature) -> i32 {
    handler::enable_feature(feature.0)
}

pub mod log {
    pub enum Level {
        Debug = -1,
        Info = 0,
        Warn = 1,
        Error = 2,
        None = 3,
    }
    use super::handler;

    ///writes a message to the host's logs at the given level.
    pub fn write(level: Level, message: &str) {
        if message.is_empty() {
            return;
        }
        handler::log(level as i32, message.as_bytes());
    }
    pub fn enabled(level: Level) -> bool {
        handler::log_enabled(level as i32)
    }
}

static KIND_REQ: i32 = 0;
static KIND_RES: i32 = 1;

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Bytes(Box<[u8]>);
impl Bytes {
    pub fn as_str(&self) -> &str {
        std::str::from_utf8(&self.0).unwrap_or_default()
    }
}
impl Deref for Bytes {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        self.0.as_ref()
    }
}
impl Display for Bytes {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.as_str())
    }
}
impl From<&str> for Bytes {
    fn from(value: &str) -> Self {
        Self(value.as_bytes().to_vec().into_boxed_slice())
    }
}

pub struct Header {
    kind: i32,
}
impl Header {
    pub fn names(&self) -> Vec<Bytes> {
        handler::header_names(self.kind)
            .iter()
            .map(|h| Bytes(h.clone()))
            .collect()
    }
    pub fn values(&self, name: &Bytes) -> Vec<Bytes> {
        handler::header_values(self.kind, name)
            .iter()
            .map(|h| Bytes(h.clone()))
            .collect()
    }
    pub fn set(&self, name: &Bytes, value: &Bytes) {
        handler::set_header(self.kind, name, value);
    }
    pub fn add(&self, name: &Bytes, value: &Bytes) {
        handler::add_header_value(self.kind, name, value);
    }
    pub fn remove(&self, name: &Bytes) {
        handler::remove_header(self.kind, name);
    }
}
pub struct Body {
    kind: i32,
}
impl Body {
    pub fn read(&self) -> Bytes {
        Bytes(handler::body(self.kind).unwrap_or_default())
    }
    pub fn write(&self, body: &Bytes) {
        handler::write_body(self.kind, body);
    }
}

pub struct Request {
    header: Header,
    body: Body,
}

impl Default for Request {
    fn default() -> Self {
        Self::new()
    }
}

impl Request {
    pub fn new() -> Self {
        Self {
            header: Header { kind: KIND_REQ },
            body: Body { kind: KIND_REQ },
        }
    }
    pub fn source_addr(&self) -> Bytes {
        Bytes(handler::source_addr().unwrap_or_default())
    }
    /// the version of the http-request
    pub fn version(&self) -> Bytes {
        Bytes(handler::version().unwrap_or_default())
    }
    pub fn method(&self) -> Bytes {
        Bytes(handler::method().unwrap_or_default())
    }
    pub fn set_method(&self, method: &Bytes) {
        handler::set_method(method);
    }
    pub fn uri(&self) -> Bytes {
        Bytes(handler::uri().unwrap_or_default())
    }
    pub fn set_uri(&self, uri: &Bytes) {
        handler::set_uri(uri);
    }
    pub fn header(&self) -> &Header {
        &self.header
    }
    pub fn body(&self) -> &Body {
        &self.body
    }
}
pub struct Response {
    header: Header,
    body: Body,
}

impl Default for Response {
    fn default() -> Self {
        Self::new()
    }
}

impl Response {
    pub fn new() -> Self {
        Self {
            header: Header { kind: KIND_RES },
            body: Body { kind: KIND_RES },
        }
    }
    pub fn status(&self) -> i32 {
        handler::status_code()
    }
    pub fn set_status(&self, code: i32) {
        handler::set_status_code(code);
    }
    pub fn header(&self) -> &Header {
        &self.header
    }
    pub fn body(&self) -> &Body {
        &self.body
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_bytes_empty() {
        let b = Bytes(b"".to_vec().into_boxed_slice());
        assert_eq!(b.is_empty(), true);
    }
    #[test]
    fn test_bytes_eq() {
        let b = Bytes(b"test".to_vec().into_boxed_slice());
        assert_eq!(b, Bytes::from("test"));
    }
}