Skip to main content

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