#![no_std]
#![feature(doc_auto_cfg)]
#![feature(macro_metavar_expr)]
#![feature(never_type)]
extern crate alloc;
use alloc::boxed::Box;
use wasefire_error::Error;
use wasefire_wire::Wire;
#[cfg(feature = "host")]
use wasefire_wire::Yoke;
pub mod applet;
pub mod platform;
pub trait Service: 'static {
#[cfg(feature = "host")]
const VERSIONS: Versions;
type Request<'a>: Wire<'a>;
type Response<'a>: Wire<'a>;
#[cfg(feature = "host")]
fn request(x: Self::Request<'_>) -> Api<Request>;
}
#[derive(Debug)]
pub enum Request {}
impl sealed::Direction for Request {
type Type<'a, T: Service> = T::Request<'a>;
}
#[derive(Debug)]
#[cfg(feature = "_descriptor")]
pub enum Response {}
#[cfg(feature = "_descriptor")]
impl sealed::Direction for Response {
type Type<'a, T: Service> = T::Response<'a>;
}
mod sealed {
pub trait Direction: 'static {
type Type<'a, T: crate::Service>: wasefire_wire::Wire<'a>;
}
}
#[derive(Wire)]
#[wire(static = T, range = 2)]
pub enum ApiResult<'a, T: Service> {
#[wire(tag = 0)]
Ok(T::Response<'a>),
#[wire(tag = 1)]
Err(Error),
}
impl<'a> Api<'a, Request> {
#[cfg(feature = "host")]
pub fn encode(&self) -> Result<Box<[u8]>, Error> {
wasefire_wire::encode(self)
}
#[cfg(feature = "device")]
pub fn decode(data: &'a [u8]) -> Result<Self, Error> {
wasefire_wire::decode(data)
}
}
impl<'a, T: Service> ApiResult<'a, T> {
#[cfg(feature = "device")]
pub fn encode(&self) -> Result<Box<[u8]>, Error> {
wasefire_wire::encode(self)
}
#[cfg(feature = "host")]
pub fn decode(data: &[u8]) -> Result<ApiResult<T>, Error> {
wasefire_wire::decode(data)
}
#[cfg(feature = "host")]
pub fn decode_yoke(data: Box<[u8]>) -> Result<Yoke<ApiResult<'static, T>>, Error> {
wasefire_wire::decode_yoke(data)
}
}
#[derive(Debug, Copy, Clone, Wire)]
#[cfg(any(feature = "host", feature = "_descriptor"))]
pub struct Versions {
pub min: u32,
pub max: Option<u32>,
}
#[cfg(feature = "host")]
impl Versions {
pub fn contains(&self, version: u32) -> Result<bool, Error> {
match (self.min, self.max) {
(min, Some(max)) => Ok((min ..= max).contains(&version)),
(min, None) if version < min => Ok(false),
(_, None) if VERSION < version => Err(Error::world(wasefire_error::Code::OutOfBounds)),
_ => Ok(true),
}
}
}
#[derive(Debug, Clone, Wire)]
#[cfg(feature = "_descriptor")]
pub struct Descriptor {
pub tag: u32,
pub versions: Versions,
}
#[cfg(feature = "_descriptor")]
impl core::fmt::Display for Descriptor {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let Descriptor { tag, versions: Versions { min, max } } = *self;
match max {
Some(max) => write!(f, "{tag} [{min} - {max}]"),
None => write!(f, "{tag} [{min} -]"),
}
}
}
macro_rules! api {
($(#![$api:meta])* version = $version:literal; next = $next:literal; $(
$(#[doc = $doc:literal])*
$tag:literal [$min:literal - $($max:literal)?] $Name:ident: $request:ty => $response:ty
),*$(,)?) => {
$(#[$api])* #[derive(Debug, Wire)]
#[wire(static = T)]
#[cfg_attr(feature = "host", wire(range = $next))]
#[cfg_attr(not(feature = "_exhaustive"), non_exhaustive)]
pub enum Api<'a, T: sealed::Direction> {
$(
$(#[doc = $doc])* $(#[cfg(feature = "host")] ${ignore($max)})? #[wire(tag = $tag)]
$Name(T::Type<'a, $Name>),
)*
}
$(
$(#[doc = $doc])* $(#[cfg(feature = "host")] ${ignore($max)})? #[derive(Debug)]
pub enum $Name {}
$(#[cfg(feature = "host")] ${ignore($max)})?
impl Service for $Name {
#[cfg(feature = "host")]
const VERSIONS: Versions = api!(versions $min $($max)?);
type Request<'a> = $request;
type Response<'a> = $response;
#[cfg(feature = "host")]
fn request(x: Self::Request<'_>) -> Api<Request> { Api::$Name(x) }
}
)*
pub const VERSION: u32 = $version;
#[cfg(feature = "_descriptor")]
pub const DESCRIPTORS: &'static [Descriptor] = &[
$(
$(#[cfg(feature = "host")] ${ignore($max)})?
Descriptor { tag: $tag, versions: api!(versions $min $($max)?) },
)*
];
};
(max) => (None);
(max $max:literal) => (Some($max));
(versions $min:literal $($max:literal)?) => (Versions { min: $min, max: api!(max $($max)?) });
}
api! {
version = 2;
next = 7;
0 [0 -] ApiVersion: () => u32,
1 [0 -] AppletRequest: applet::Request<'a> => (),
2 [0 -] AppletResponse: applet::AppletId => applet::Response<'a>,
3 [0 -] PlatformReboot: () => !,
4 [0 -] AppletTunnel: applet::Tunnel<'a> => (),
5 [1 -] PlatformInfo: () => platform::Info<'a>,
6 [2 -] PlatformVendor: &'a [u8] => &'a [u8],
}