use core::marker::PhantomData;
use std::collections::BTreeMap;
use crate::{
Capability, ChannelCreate, GuestResourceId, GuestUint, IoFrame, IoRead, IoWrite, NetAccept,
NetAcceptReply, NetConnect, NetConnectReply, NetCreateListener, NetCreateListenerReply,
NetTlsClientConfig, NetTlsConfigReply, NetTlsServerConfig, ProcessLogLookup,
ProcessLogRegistration, ProcessStart, RkyvEncode, SessionCreate, SessionEntitlement,
SessionRemove, SessionResource, SingletonLookup, SingletonRegister, TimeNow, TimeSleep,
};
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct HostcallMeta {
pub name: &'static str,
pub capability: Capability,
}
pub struct Hostcall<I, O> {
meta: HostcallMeta,
_marker: PhantomData<(I, O)>,
}
impl<I, O> Hostcall<I, O>
where
I: RkyvEncode + Send,
O: RkyvEncode + Send,
for<'a> I::Archived: 'a
+ rkyv::Deserialize<I, rkyv::api::high::HighDeserializer<rkyv::rancor::Error>>
+ rkyv::bytecheck::CheckBytes<rkyv::api::high::HighValidator<'a, rkyv::rancor::Error>>,
for<'a> O::Archived: 'a
+ rkyv::Deserialize<O, rkyv::api::high::HighDeserializer<rkyv::rancor::Error>>
+ rkyv::bytecheck::CheckBytes<rkyv::api::high::HighValidator<'a, rkyv::rancor::Error>>,
{
pub const fn new(name: &'static str, capability: Capability) -> Self {
Self {
meta: HostcallMeta { name, capability },
_marker: PhantomData,
}
}
pub const fn name(&self) -> &'static str {
self.meta.name
}
pub const fn capability(&self) -> Capability {
self.meta.capability
}
pub const fn meta(&self) -> HostcallMeta {
self.meta
}
}
macro_rules! declare_hostcalls {
(
$( $ident:ident => {
name: $name:literal,
capability: $cap:path,
input: $input:ty,
output: $output:ty
}, )+
) => {
$(
#[doc = concat!("Hostcall descriptor for `", $name, "`.")]
pub const $ident: Hostcall<$input, $output> = Hostcall::new($name, $cap);
)+
pub const ALL: &[HostcallMeta] = &[
$(HostcallMeta { name: $name, capability: $cap },)+
];
pub fn by_capability() -> BTreeMap<Capability, Vec<&'static HostcallMeta>> {
let mut map = BTreeMap::new();
for meta in ALL {
map.entry(meta.capability)
.or_insert_with(Vec::new)
.push(meta);
}
map
}
#[doc = "Expand to the canonical hostcall symbol name for the given identifier."]
#[macro_export]
macro_rules! hostcall_name {
$(($ident) => { $name };)+
($other:ident) => {
compile_error!(concat!("unknown hostcall: ", stringify!($other)))
};
}
#[doc = "Expand to the typed hostcall descriptor for the given identifier."]
#[macro_export]
macro_rules! hostcall_contract {
$(($ident) => { &$crate::hostcalls::$ident };)+
($other:ident) => {
compile_error!(concat!("unknown hostcall: ", stringify!($other)))
};
}
};
}
declare_hostcalls! {
SESSION_CREATE => {
name: "selium::session::create",
capability: Capability::SessionLifecycle,
input: SessionCreate,
output: u32
},
SESSION_REMOVE => {
name: "selium::session::remove",
capability: Capability::SessionLifecycle,
input: SessionRemove,
output: ()
},
SESSION_ADD_ENTITLEMENT => {
name: "selium::session::add_entitlement",
capability: Capability::SessionLifecycle,
input: SessionEntitlement,
output: ()
},
SESSION_RM_ENTITLEMENT => {
name: "selium::session::rm_entitlement",
capability: Capability::SessionLifecycle,
input: SessionEntitlement,
output: ()
},
SESSION_ADD_RESOURCE => {
name: "selium::session::add_resource",
capability: Capability::SessionLifecycle,
input: SessionResource,
output: u32
},
SESSION_RM_RESOURCE => {
name: "selium::session::rm_resource",
capability: Capability::SessionLifecycle,
input: SessionResource,
output: u32
},
CHANNEL_CREATE => {
name: "selium::channel::create",
capability: Capability::ChannelLifecycle,
input: ChannelCreate,
output: GuestUint
},
CHANNEL_DELETE => {
name: "selium::channel::delete",
capability: Capability::ChannelLifecycle,
input: GuestUint,
output: ()
},
CHANNEL_DRAIN => {
name: "selium::channel::drain",
capability: Capability::ChannelLifecycle,
input: u32,
output: ()
},
CHANNEL_SHARE => {
name: "selium::channel::share",
capability: Capability::ChannelLifecycle,
input: GuestUint,
output: GuestResourceId
},
CHANNEL_ATTACH => {
name: "selium::channel::attach",
capability: Capability::ChannelLifecycle,
input: GuestResourceId,
output: GuestUint
},
CHANNEL_DETACH => {
name: "selium::channel::detach",
capability: Capability::ChannelLifecycle,
input: GuestUint,
output: ()
},
PROCESS_REGISTER_LOG => {
name: "selium::process::register_log_channel",
capability: Capability::ChannelLifecycle,
input: ProcessLogRegistration,
output: ()
},
SINGLETON_REGISTER => {
name: "selium::singleton::register",
capability: Capability::SingletonRegistry,
input: SingletonRegister,
output: ()
},
SINGLETON_LOOKUP => {
name: "selium::singleton::lookup",
capability: Capability::SingletonLookup,
input: SingletonLookup,
output: GuestResourceId
},
TIME_NOW => {
name: "selium::time::now",
capability: Capability::TimeRead,
input: (),
output: TimeNow
},
TIME_SLEEP => {
name: "selium::time::sleep",
capability: Capability::TimeRead,
input: TimeSleep,
output: ()
},
CHANNEL_STRONG_READER_CREATE => {
name: "selium::channel::strong_reader_create",
capability: Capability::ChannelReader,
input: GuestUint,
output: GuestUint
},
CHANNEL_WEAK_READER_CREATE => {
name: "selium::channel::weak_reader_create",
capability: Capability::ChannelReader,
input: GuestUint,
output: GuestUint
},
CHANNEL_STRONG_READ => {
name: "selium::channel::strong_read",
capability: Capability::ChannelReader,
input: IoRead,
output: IoFrame
},
CHANNEL_WEAK_READ => {
name: "selium::channel::weak_read",
capability: Capability::ChannelReader,
input: IoRead,
output: IoFrame
},
CHANNEL_STRONG_WRITER_CREATE => {
name: "selium::channel::strong_writer_create",
capability: Capability::ChannelWriter,
input: GuestUint,
output: GuestUint
},
CHANNEL_WEAK_WRITER_CREATE => {
name: "selium::channel::weak_writer_create",
capability: Capability::ChannelWriter,
input: GuestUint,
output: GuestUint
},
CHANNEL_WRITER_DOWNGRADE => {
name: "selium::channel::writer_downgrade",
capability: Capability::ChannelWriter,
input: GuestUint,
output: GuestUint
},
CHANNEL_STRONG_WRITE => {
name: "selium::channel::strong_write",
capability: Capability::ChannelWriter,
input: IoWrite,
output: GuestUint
},
CHANNEL_WEAK_WRITE => {
name: "selium::channel::weak_write",
capability: Capability::ChannelWriter,
input: IoWrite,
output: GuestUint
},
PROCESS_LOG_CHANNEL => {
name: "selium::process::log_channel",
capability: Capability::ProcessLifecycle,
input: ProcessLogLookup,
output: GuestResourceId
},
PROCESS_START => {
name: "selium::process::start",
capability: Capability::ProcessLifecycle,
input: ProcessStart,
output: GuestResourceId
},
PROCESS_STOP => {
name: "selium::process::stop",
capability: Capability::ProcessLifecycle,
input: GuestResourceId,
output: ()
},
NET_QUIC_BIND => {
name: "selium::net::quic::bind",
capability: Capability::NetQuicBind,
input: NetCreateListener,
output: NetCreateListenerReply
},
NET_QUIC_ACCEPT => {
name: "selium::net::quic::accept",
capability: Capability::NetQuicAccept,
input: NetAccept,
output: NetAcceptReply
},
NET_QUIC_CONNECT => {
name: "selium::net::quic::connect",
capability: Capability::NetQuicConnect,
input: NetConnect,
output: NetConnectReply
},
NET_QUIC_READ => {
name: "selium::net::quic::read",
capability: Capability::NetQuicRead,
input: IoRead,
output: IoFrame
},
NET_QUIC_WRITE => {
name: "selium::net::quic::write",
capability: Capability::NetQuicWrite,
input: IoWrite,
output: GuestUint
},
NET_HTTP_BIND => {
name: "selium::net::http::bind",
capability: Capability::NetHttpBind,
input: NetCreateListener,
output: NetCreateListenerReply
},
NET_HTTP_ACCEPT => {
name: "selium::net::http::accept",
capability: Capability::NetHttpAccept,
input: NetAccept,
output: NetAcceptReply
},
NET_HTTP_CONNECT => {
name: "selium::net::http::connect",
capability: Capability::NetHttpConnect,
input: NetConnect,
output: NetConnectReply
},
NET_HTTP_READ => {
name: "selium::net::http::read",
capability: Capability::NetHttpRead,
input: IoRead,
output: IoFrame
},
NET_HTTP_WRITE => {
name: "selium::net::http::write",
capability: Capability::NetHttpWrite,
input: IoWrite,
output: GuestUint
},
NET_TLS_SERVER_CONFIG_CREATE => {
name: "selium::net::tls::server_config_create",
capability: Capability::NetTlsServerConfig,
input: NetTlsServerConfig,
output: NetTlsConfigReply
},
NET_TLS_CLIENT_CONFIG_CREATE => {
name: "selium::net::tls::client_config_create",
capability: Capability::NetTlsClientConfig,
input: NetTlsClientConfig,
output: NetTlsConfigReply
},
}