trussed_core/
client.rs

1use core::{marker::PhantomData, task::Poll};
2
3use crate::{
4    api::{Reply, ReplyVariant, RequestVariant},
5    error::{Error, Result},
6    interrupt::InterruptFlag,
7};
8
9#[cfg(feature = "attestation-client")]
10pub mod attestation;
11#[cfg(feature = "certificate-client")]
12pub mod certificate;
13#[cfg(feature = "counter-client")]
14pub mod counter;
15#[cfg(feature = "crypto-client")]
16pub mod crypto;
17#[cfg(feature = "filesystem-client")]
18pub mod filesystem;
19#[cfg(feature = "management-client")]
20pub mod management;
21#[cfg(feature = "ui-client")]
22pub mod ui;
23
24// to be fair, this is a programmer error,
25// and could also just panic
26#[derive(Copy, Clone, Debug)]
27#[non_exhaustive]
28pub enum ClientError {
29    Full,
30    Pending,
31    DataTooLarge,
32    SerializationFailed,
33}
34
35pub type ClientResult<'c, T, C> = Result<FutureResult<'c, T, C>, ClientError>;
36
37/// Lowest level interface, use one of the higher level ones.
38pub trait PollClient {
39    fn request<Rq: RequestVariant>(&mut self, req: Rq) -> ClientResult<'_, Rq::Reply, Self>;
40    fn poll(&mut self) -> Poll<Result<Reply, Error>>;
41    fn interrupt(&self) -> Option<&'static InterruptFlag> {
42        None
43    }
44}
45
46#[must_use = "Syscalls must be polled with the `syscall` macro"]
47pub struct FutureResult<'c, T, C: ?Sized>
48where
49    C: PollClient,
50{
51    pub(crate) client: &'c mut C,
52    __: PhantomData<T>,
53}
54
55impl<'c, T, C> FutureResult<'c, T, C>
56where
57    T: ReplyVariant,
58    C: PollClient,
59{
60    pub fn new(client: &'c mut C) -> Self {
61        Self {
62            client,
63            __: PhantomData,
64        }
65    }
66    pub fn poll(&mut self) -> Poll<Result<T, Error>> {
67        self.client
68            .poll()
69            .map(|result| result.and_then(TryFrom::try_from))
70    }
71}
72
73// would be interesting to use proper futures, and something like
74// https://github.com/dflemstr/direct-executor/blob/master/src/lib.rs#L62-L66
75
76#[macro_export]
77// #[deprecated]
78macro_rules! block {
79    ($future_result:expr) => {{
80        // evaluate the expression
81        let mut future_result = $future_result;
82        loop {
83            match future_result.poll() {
84                core::task::Poll::Ready(result) => {
85                    break result;
86                }
87                core::task::Poll::Pending => {}
88            }
89        }
90    }};
91}
92
93#[macro_export]
94macro_rules! syscall {
95    ($pre_future_result:expr) => {{
96        // evaluate the expression
97        let mut future_result = $pre_future_result.expect("no client error");
98        loop {
99            match future_result.poll() {
100                core::task::Poll::Ready(result) => {
101                    break result.expect("no errors");
102                }
103                core::task::Poll::Pending => {}
104            }
105        }
106    }};
107}
108
109#[macro_export]
110macro_rules! try_syscall {
111    ($pre_future_result:expr) => {{
112        // evaluate the expression
113        let mut future_result = $pre_future_result.expect("no client error");
114        loop {
115            match future_result.poll() {
116                core::task::Poll::Ready(result) => {
117                    break result;
118                }
119                core::task::Poll::Pending => {}
120            }
121        }
122    }};
123}