server/
owned.rs

1// SPDX-FileCopyrightText: 2025 Foundation Devices, Inc. <hello@foundation.xyz>
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4use std::{marker::PhantomData, ops::Deref};
5
6use rkyv::{bytecheck::CheckBytes, rancor};
7use xous_ipc::{XousDeserializer, XousValidator};
8
9use crate::WrongMessageTypeError;
10
11pub struct Owned<T> {
12    envelope: xous::MessageEnvelope,
13    _marker: PhantomData<T>,
14}
15
16impl<T> std::fmt::Debug for Owned<T>
17where
18    T: rkyv::Archive,
19    T::Archived: std::fmt::Debug,
20{
21    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22        f.debug_tuple("Owned").field(&*self).finish()
23    }
24}
25
26impl<T> Owned<T>
27where
28    T: rkyv::Archive,
29    T::Archived: rkyv::Portable,
30{
31    pub fn new(envelope: xous::MessageEnvelope) -> Result<Self, rancor::Error>
32    where
33        T::Archived: for<'a> CheckBytes<XousValidator<'a>>,
34    {
35        match envelope.body.memory_message() {
36            Some(mem) => rkyv::api::low::access::<T::Archived, rancor::Error>(as_slice(mem))?,
37            None => rancor::fail!(WrongMessageTypeError),
38        };
39
40        Ok(Self { envelope, _marker: Default::default() })
41    }
42
43    pub fn new_move(envelope: xous::MessageEnvelope) -> Result<Self, rancor::Error>
44    where
45        T::Archived: for<'a> CheckBytes<XousValidator<'a>>,
46    {
47        match &envelope.body {
48            xous::Message::Move(mem) => rkyv::api::low::access::<T::Archived, rancor::Error>(as_slice(mem))?,
49            _ => rancor::fail!(WrongMessageTypeError),
50        };
51
52        Ok(Self { envelope, _marker: Default::default() })
53    }
54
55    #[inline]
56    pub fn deserialize(&self) -> Result<T, rancor::Error>
57    where
58        T::Archived: rkyv::Deserialize<T, XousDeserializer>,
59    {
60        rkyv::api::low::deserialize(self.access())
61    }
62
63    #[inline]
64    pub fn access(&self) -> &T::Archived { unsafe { rkyv::access_unchecked(self.as_slice()) } }
65}
66
67impl<T> Owned<T>
68where
69    T: rkyv::Archive,
70    T::Archived: rkyv::Portable,
71{
72    #[inline]
73    fn as_memory_message(&self) -> &xous::MemoryMessage {
74        match self.envelope.body.memory_message() {
75            Some(mem) => mem,
76            None => unreachable!("message was already checked in Owned::new"),
77        }
78    }
79
80    #[inline]
81    pub fn as_slice(&self) -> &[u8] { as_slice(self.as_memory_message()) }
82}
83
84impl<T> Deref for Owned<T>
85where
86    T: rkyv::Archive,
87    T::Archived: rkyv::Portable,
88{
89    type Target = T::Archived;
90
91    #[inline]
92    fn deref(&self) -> &Self::Target { self.access() }
93}
94
95#[inline]
96fn as_slice(mem: &xous::MemoryMessage) -> &[u8] {
97    let slice = mem.buf.as_slice();
98    let used = mem.offset.map_or(0, |v| v.get()).min(slice.len());
99    &slice[..used]
100}