trussed_core/
serde_extensions.rs

1//! Extensions to the core Trussed syscalls.
2//!
3//! *Requires the `serde-extensions` feature.*
4//!
5//! This module makes it possible to add additional syscalls to Trussed by implementing the
6//! [`Extension`][] trait.  Extension requests and replies are serialized to
7//! [`Request::SerdeExtension`][] and [`Reply::SerdeExtension`][].
8//!
9//! [`Request::SerdeExtension`]: `crate::api::Request::SerdeExtension`
10//! [`Reply::SerdeExtension`]: `crate::api::Reply::SerdeExtension`
11
12use core::{marker::PhantomData, task::Poll};
13
14use serde::{de::DeserializeOwned, Serialize};
15
16use crate::{
17    api::{reply, request},
18    client::{ClientError, FutureResult, PollClient},
19    error::Error,
20    types::Bytes,
21};
22
23/// A Trussed API extension.
24pub trait Extension {
25    /// The requests supported by this extension.
26    type Request: DeserializeOwned + Serialize;
27    /// The replies supported by this extension.
28    type Reply: DeserializeOwned + Serialize;
29
30    /// Serialize an extension request.
31    ///
32    /// Requests that are serialized with this function can be deserialized with
33    /// [`Extension::deserialize_request`][].  The format is not guaranteed to be stable over
34    /// crate releases.
35    #[inline(never)]
36    fn serialize_request(
37        id: u8,
38        request: &Self::Request,
39    ) -> Result<request::SerdeExtension, ClientError> {
40        postcard::to_vec(request)
41            .map(Bytes::from)
42            .map(|request| request::SerdeExtension { id, request })
43            .map_err(|_| ClientError::SerializationFailed)
44    }
45
46    /// Deserialize an extension request.
47    ///
48    /// This function can be used to deserialize requests that have been serialized with
49    /// [`Extension::serialize_request`][].  The format is not guaranteed to be stable over
50    /// crate releases.
51    #[inline(never)]
52    fn deserialize_request(request: &request::SerdeExtension) -> Result<Self::Request, Error> {
53        postcard::from_bytes(&request.request).map_err(|_| Error::InvalidSerializedRequest)
54    }
55
56    /// Serialize an extension reply.
57    ///
58    /// Replies that are serialized with this function can be deserialized with
59    /// [`Extension::deserialize_reply`][].  The format is not guaranteed to be stable over
60    /// crate releases.
61    #[inline(never)]
62    fn serialize_reply(reply: &Self::Reply) -> Result<reply::SerdeExtension, Error> {
63        postcard::to_vec(reply)
64            .map(Bytes::from)
65            .map(|reply| reply::SerdeExtension { reply })
66            .map_err(|_| Error::ReplySerializationFailure)
67    }
68
69    /// Deserialize an extension reply.
70    ///
71    /// This function can be used to deserialize replies that have been serialized with
72    /// [`Extension::serialize_reply`][].  The format is not guaranteed to be stable over
73    /// crate releases.
74    #[inline(never)]
75    fn deserialize_reply(reply: &reply::SerdeExtension) -> Result<Self::Reply, Error> {
76        postcard::from_bytes(&reply.reply).map_err(|_| Error::InvalidSerializedReply)
77    }
78}
79
80/// Executes extension requests.
81///
82/// Instead of using this trait directly, extensions should define their own traits that extend
83/// this trait and use the `extension` function to execute extension requests.
84pub trait ExtensionClient<E: Extension>: PollClient {
85    /// Returns the ID for the `E` extension as defined by the runner.
86    fn id() -> u8;
87
88    /// Executes an extension request.
89    ///
90    /// Applications should not call this method directly and instead use a trait provided by the
91    /// extension.
92    fn extension<Rq, Rp>(&mut self, request: Rq) -> ExtensionResult<'_, E, Rp, Self>
93    where
94        Rq: Into<E::Request>,
95        Rp: TryFrom<E::Reply, Error = Error>,
96    {
97        let request = E::serialize_request(Self::id(), &request.into())?;
98        self.request(request).map(From::from)
99    }
100}
101
102/// A result returned by [`ExtensionClient`][] and clients using it.
103pub type ExtensionResult<'a, E, T, C> = Result<ExtensionFutureResult<'a, E, T, C>, ClientError>;
104
105#[must_use = "Syscalls must be polled with the `syscall` macro"]
106/// A future of an [`ExtensionResult`][].
107pub struct ExtensionFutureResult<'c, E, T, C: ?Sized> {
108    client: &'c mut C,
109    __: PhantomData<(E, T)>,
110}
111
112impl<'c, E, T, C: ?Sized> ExtensionFutureResult<'c, E, T, C> {
113    fn new(client: &'c mut C) -> Self {
114        Self {
115            client,
116            __: PhantomData,
117        }
118    }
119}
120
121impl<E, T, C> ExtensionFutureResult<'_, E, T, C>
122where
123    E: Extension,
124    T: TryFrom<E::Reply, Error = Error>,
125    C: PollClient,
126{
127    pub fn poll(&mut self) -> Poll<Result<T, Error>> {
128        self.client.poll().map(|result| {
129            result.and_then(|reply| {
130                let reply = reply::SerdeExtension::try_from(reply)?;
131                let reply: E::Reply = E::deserialize_reply(&reply)?;
132                reply.try_into()
133            })
134        })
135    }
136}
137
138impl<'c, E, T, C> From<FutureResult<'c, reply::SerdeExtension, C>>
139    for ExtensionFutureResult<'c, E, T, C>
140where
141    C: PollClient + ?Sized,
142{
143    fn from(result: FutureResult<'c, reply::SerdeExtension, C>) -> Self {
144        Self::new(result.client)
145    }
146}