use core::{marker::PhantomData, task::Poll};
use crate::{
api::{Reply, ReplyVariant, RequestVariant},
error::{Error, Result},
interrupt::InterruptFlag,
};
#[cfg(feature = "attestation-client")]
pub mod attestation;
#[cfg(feature = "certificate-client")]
pub mod certificate;
#[cfg(feature = "counter-client")]
pub mod counter;
#[cfg(feature = "crypto-client")]
pub mod crypto;
#[cfg(feature = "filesystem-client")]
pub mod filesystem;
#[cfg(feature = "management-client")]
pub mod management;
#[cfg(feature = "ui-client")]
pub mod ui;
#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
pub enum ClientError {
Full,
Pending,
DataTooLarge,
SerializationFailed,
}
pub type ClientResult<'c, T, C> = Result<FutureResult<'c, T, C>, ClientError>;
pub trait PollClient {
fn request<Rq: RequestVariant>(&mut self, req: Rq) -> ClientResult<'_, Rq::Reply, Self>;
fn poll(&mut self) -> Poll<Result<Reply, Error>>;
fn interrupt(&self) -> Option<&'static InterruptFlag> {
None
}
}
#[must_use = "Syscalls must be polled with the `syscall` macro"]
pub struct FutureResult<'c, T, C: ?Sized>
where
C: PollClient,
{
pub(crate) client: &'c mut C,
__: PhantomData<T>,
}
impl<'c, T, C> FutureResult<'c, T, C>
where
T: ReplyVariant,
C: PollClient,
{
pub fn new(client: &'c mut C) -> Self {
Self {
client,
__: PhantomData,
}
}
pub fn poll(&mut self) -> Poll<Result<T, Error>> {
self.client
.poll()
.map(|result| result.and_then(TryFrom::try_from))
}
}
#[macro_export]
macro_rules! block {
($future_result:expr) => {{
let mut future_result = $future_result;
loop {
match future_result.poll() {
core::task::Poll::Ready(result) => {
break result;
}
core::task::Poll::Pending => {}
}
}
}};
}
#[macro_export]
macro_rules! syscall {
($pre_future_result:expr) => {{
let mut future_result = $pre_future_result.expect("no client error");
loop {
match future_result.poll() {
core::task::Poll::Ready(result) => {
break result.expect("no errors");
}
core::task::Poll::Pending => {}
}
}
}};
}
#[macro_export]
macro_rules! try_syscall {
($pre_future_result:expr) => {{
let mut future_result = $pre_future_result.expect("no client error");
loop {
match future_result.poll() {
core::task::Poll::Ready(result) => {
break result;
}
core::task::Poll::Pending => {}
}
}
}};
}