Skip to main content
KeyOS API Reference

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};
7
8use crate::WrongMessageTypeError;
9use crate::{XousDeserializer, XousValidator};
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::<T, rancor::Error>(self.access())
61    }
62
63    #[inline]
64    pub fn access(&self) -> &T::Archived {
65        // SAFETY: the archive was validated in `Owned::new`/`new_move`.
66        unsafe { rkyv::access_unchecked::<T::Archived>(self.as_slice()) }
67    }
68}
69
70impl<T> Owned<T>
71where
72    T: rkyv::Archive,
73    T::Archived: rkyv::Portable,
74{
75    #[inline]
76    fn as_memory_message(&self) -> &xous::MemoryMessage {
77        match self.envelope.body.memory_message() {
78            Some(mem) => mem,
79            None => unreachable!("message was already checked in Owned::new"),
80        }
81    }
82
83    #[inline]
84    pub fn as_slice(&self) -> &[u8] { as_slice(self.as_memory_message()) }
85}
86
87impl<T> Deref for Owned<T>
88where
89    T: rkyv::Archive,
90    T::Archived: rkyv::Portable,
91{
92    type Target = T::Archived;
93
94    #[inline]
95    fn deref(&self) -> &Self::Target { self.access() }
96}
97
98#[inline]
99fn as_slice(mem: &xous::MemoryMessage) -> &[u8] {
100    let slice = mem.buf.as_slice();
101    &slice[..crate::Buffer::message_len(mem)]
102}