pub use postcard::Error;
pub use status_code::StatusCode;
pub use url::{Scheme, Url};
mod status_code;
mod url;
pub mod cells;
pub type SessionId = uuid::Uuid;
#[allow(clippy::large_enum_variant)]
#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Incoming<'a> {
Message(#[serde(borrow)] Message<'a>),
ConnectionUp(ConnectionUp),
ConnectionDown(ConnectionDown),
Request(#[serde(borrow)] HttpRequest<'a>),
}
impl<'a> Incoming<'a> {
pub fn encode<'b>(&self, buffer: &'b mut [u8]) -> Result<&'b mut [u8], Error> {
postcard::to_slice(self, buffer)
}
#[cfg(feature = "alloc")]
pub fn encode_to_vec(&self) -> Result<alloc::vec::Vec<u8>, Error> {
postcard::to_allocvec(self)
}
pub fn write_to<W>(&self, writer: W) -> Result<W, Error>
where
W: Extend<u8>,
{
postcard::to_extend(self, writer)
}
pub fn decode(buffer: &'a [u8]) -> Result<(Self, &'a [u8]), Error> {
postcard::take_from_bytes(buffer)
}
pub fn ctx(&self) -> SessionId {
match self {
Self::Message(v) => v.ctx,
Self::ConnectionUp(v) => v.ctx,
Self::ConnectionDown(v) => v.ctx,
Self::Request(v) => v.ctx,
}
}
pub fn message(ctx: SessionId, data: &'a [u8]) -> Self {
Self::Message(Message { ctx, data })
}
pub fn connection_up(ctx: SessionId) -> Self {
Self::ConnectionUp(ConnectionUp { ctx })
}
pub fn connection_down(ctx: SessionId) -> Self {
Self::ConnectionDown(ConnectionDown { ctx })
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Outgoing<'a> {
Message(#[serde(borrow)] Message<'a>),
Response(#[serde(borrow)] HttpResponse<'a>),
Lookup(#[serde(borrow)] Lookup<'a>),
Upgrade(Upgrade),
Disconnect(Disconnect),
}
impl<'a> Outgoing<'a> {
pub fn encode<'b>(&self, buffer: &'b mut [u8]) -> Result<&'b mut [u8], Error> {
postcard::to_slice(self, buffer)
}
#[cfg(feature = "alloc")]
pub fn encode_to_vec(&self) -> Result<alloc::vec::Vec<u8>, Error> {
postcard::to_allocvec(self)
}
#[cfg(feature = "eio")]
pub fn to_eio<W>(&self, writer: W) -> Result<W, Error>
where
W: embedded_io::Write,
{
postcard::to_eio(self, writer)
}
pub fn write_to<W>(&self, writer: W) -> Result<W, Error>
where
W: Extend<u8>,
{
postcard::to_extend(self, writer)
}
pub fn decode(buffer: &'a [u8]) -> Result<(Self, &'a [u8]), Error> {
postcard::take_from_bytes(buffer)
}
pub fn ctx(&self) -> SessionId {
match self {
Self::Message(v) => v.ctx,
Self::Response(v) => v.ctx,
Self::Lookup(v) => v.ctx,
Self::Upgrade(v) => v.ctx,
Self::Disconnect(v) => v.ctx,
}
}
pub fn message(ctx: SessionId, data: &'a [u8]) -> Self {
Self::Message(Message { ctx, data })
}
pub fn response(response: HttpResponse<'a>) -> Self {
Self::Response(response)
}
pub fn lookup(ctx: SessionId, path: &'a str) -> Self {
Self::Lookup(Lookup { ctx, path })
}
pub fn upgrade(ctx: SessionId) -> Self {
Self::Upgrade(Upgrade { ctx })
}
pub fn disconnect(ctx: SessionId) -> Self {
Self::Disconnect(Disconnect { ctx })
}
}
pub const HEADER_MAX: usize = 8;
pub type Headers<'a> = heapless::Vec<Header<'a>, HEADER_MAX>;
#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[allow(missing_docs)]
pub struct HttpRequest<'a> {
pub ctx: SessionId,
pub method: Method,
pub path: &'a str,
#[serde(borrow)]
pub headers: Headers<'a>,
pub body: &'a [u8],
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[allow(missing_docs)]
pub struct HttpResponse<'a> {
pub ctx: SessionId,
pub status_code: StatusCode,
#[serde(borrow)]
pub headers: Headers<'a>,
pub body: &'a [u8],
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[allow(missing_docs)]
pub struct Header<'a> {
#[serde(borrow)]
pub name: &'a str,
#[serde(borrow)]
pub value: &'a str,
}
#[derive(
Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, serde::Serialize, serde::Deserialize,
)]
#[repr(u8)]
#[allow(missing_docs)]
pub enum Method {
Options,
Get,
Post,
Put,
Delete,
Head,
Trace,
Connect,
Patch,
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[allow(missing_docs)]
pub struct Message<'a> {
pub ctx: SessionId,
#[serde(borrow)]
pub data: &'a [u8],
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[allow(missing_docs)]
pub struct ConnectionUp {
pub ctx: SessionId,
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[allow(missing_docs)]
pub struct ConnectionDown {
pub ctx: SessionId,
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[allow(missing_docs)]
pub struct Disconnect {
pub ctx: SessionId,
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[allow(missing_docs)]
pub struct Lookup<'a> {
pub ctx: SessionId,
#[serde(borrow)]
pub path: &'a str,
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[allow(missing_docs)]
pub struct Upgrade {
pub ctx: SessionId,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ctx() {
let msg = Incoming::Request(HttpRequest {
ctx: Default::default(),
method: Method::Options,
path: "/",
headers: Default::default(),
body: b"this is some body",
});
let mut buffer = [0u8; 1024];
let encoded = msg.encode(&mut buffer).unwrap();
let (value, rest) = Incoming::decode(&*encoded).unwrap();
assert!(rest.is_empty());
assert_eq!(msg.ctx(), value.ctx());
}
}