use trussed_core::{
api::{reply, request, Reply, Request},
serde_extensions::{Extension, ExtensionClient},
Error,
};
use crate::{
backend::{Backend, CoreOnly, Dispatch, NoId, OptionalBackend},
client::ClientImplementation,
platform::{Platform, Syscall},
service::ServiceResources,
types::{self, Context, CoreContext},
};
pub trait ExtensionDispatch {
type BackendId: 'static;
type Context: Default;
type ExtensionId: TryFrom<u8, Error = Error>;
fn core_request<P: Platform>(
&mut self,
backend: &Self::BackendId,
ctx: &mut Context<Self::Context>,
request: &Request,
resources: &mut ServiceResources<P>,
) -> Result<Reply, Error> {
let _ = (backend, ctx, request, resources);
Err(Error::RequestNotAvailable)
}
fn extension_request<P: Platform>(
&mut self,
backend: &Self::BackendId,
extension: &Self::ExtensionId,
ctx: &mut Context<Self::Context>,
request: &request::SerdeExtension,
resources: &mut ServiceResources<P>,
) -> Result<reply::SerdeExtension, Error> {
let _ = (backend, extension, ctx, request, resources);
Err(Error::RequestNotAvailable)
}
}
impl<T: ExtensionDispatch> Dispatch for T {
type BackendId = T::BackendId;
type Context = T::Context;
fn request<P: Platform>(
&mut self,
backend: &Self::BackendId,
ctx: &mut Context<Self::Context>,
request: &Request,
resources: &mut ServiceResources<P>,
) -> Result<Reply, Error> {
if let Request::SerdeExtension(request) = &request {
T::ExtensionId::try_from(request.id)
.and_then(|extension| {
self.extension_request(backend, &extension, ctx, request, resources)
})
.map(Reply::SerdeExtension)
} else {
self.core_request(backend, ctx, request, resources)
}
}
}
impl ExtensionDispatch for CoreOnly {
type BackendId = NoId;
type Context = types::NoData;
type ExtensionId = NoId;
}
pub trait ExtensionImpl<E: Extension>: Backend {
fn extension_request<P: Platform>(
&mut self,
core_ctx: &mut CoreContext,
backend_ctx: &mut Self::Context,
request: &E::Request,
resources: &mut ServiceResources<P>,
) -> Result<E::Reply, Error>;
fn extension_request_serialized<P: Platform>(
&mut self,
core_ctx: &mut CoreContext,
backend_ctx: &mut Self::Context,
request: &request::SerdeExtension,
resources: &mut ServiceResources<P>,
) -> Result<reply::SerdeExtension, Error> {
let request = E::deserialize_request(request)?;
let reply = self.extension_request(core_ctx, backend_ctx, &request, resources)?;
E::serialize_reply(&reply)
}
}
impl<E: Extension, I: ExtensionImpl<E>> ExtensionImpl<E> for OptionalBackend<I> {
fn extension_request<P: Platform>(
&mut self,
core_ctx: &mut CoreContext,
backend_ctx: &mut Self::Context,
request: &E::Request,
resources: &mut ServiceResources<P>,
) -> Result<E::Reply, Error> {
self.inner()?
.extension_request(core_ctx, backend_ctx, request, resources)
}
}
pub trait ExtensionId<E> {
type Id: Into<u8>;
const ID: Self::Id;
}
impl<E, S, I> ExtensionClient<E> for ClientImplementation<'_, S, I>
where
E: Extension,
S: Syscall,
I: ExtensionId<E>,
{
fn id() -> u8 {
I::ID.into()
}
}