server/
lend_mut.rs

1// SPDX-FileCopyrightText: 2023 Foundation Devices, Inc. <hello@foundation.xyz>
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4use crate::{Server, ServerContext};
5
6/// A [`LendMut`] message handler.
7pub trait LendMutHandler<M: LendMut>
8where
9    Self: Server,
10{
11    fn handle(&mut self, msg: M, sender: xous::PID, context: &mut ServerContext<Self>) -> M::Response;
12}
13
14/// A message which is simply some mutably borrowed memory.
15pub trait LendMut: crate::MessageId + From<SimpleMemoryMessage> + Into<SimpleMemoryMessage> {
16    type Response: LendMutResponse;
17}
18
19pub trait LendMutResponse {
20    fn from_usize_pair(arg1: usize, arg2: usize) -> Self;
21    fn to_usize_pair(self) -> (usize, usize);
22}
23
24impl LendMutResponse for () {
25    fn from_usize_pair(_arg1: usize, _arg2: usize) {}
26
27    fn to_usize_pair(self) -> (usize, usize) { (0, 0) }
28}
29
30impl LendMutResponse for usize {
31    fn from_usize_pair(arg1: usize, _arg2: usize) -> usize { arg1 }
32
33    fn to_usize_pair(self) -> (usize, usize) { (self, 0) }
34}
35
36impl<T1: From<usize> + Into<usize>, T2: From<usize> + Into<usize>> LendMutResponse for Result<T1, T2> {
37    fn from_usize_pair(arg1: usize, arg2: usize) -> Self {
38        if arg1 == 0 {
39            Ok(arg2.into())
40        } else {
41            Err(arg2.into())
42        }
43    }
44
45    fn to_usize_pair(self) -> (usize, usize) {
46        match self {
47            Ok(o) => (0, o.into()),
48            Err(e) => (1, e.into()),
49        }
50    }
51}
52
53/// An easier to use version of [`xous::MemoryMessage`]
54pub struct SimpleMemoryMessage {
55    /// The offset of the buffer.  This address will get transformed when the
56    /// message is moved between processes.
57    pub buf: xous::MemoryRange,
58    pub arg1: usize,
59    pub arg2: usize,
60}
61
62impl From<&xous::MemoryMessage> for SimpleMemoryMessage {
63    fn from(value: &xous::MemoryMessage) -> Self {
64        Self {
65            buf: value.buf,
66            arg1: value.offset.map(|v| v.get()).unwrap_or_default(),
67            arg2: value.valid.map(|v| v.get()).unwrap_or_default(),
68        }
69    }
70}
71
72/// Message handler, used by ServerMessages::messages()
73pub fn handle_lend_mut<M: LendMut, S: LendMutHandler<M>>(
74    handler: &mut S,
75    mut raw: xous::MessageEnvelope,
76    context: &mut ServerContext<S>,
77) {
78    let xous::Message::MutableBorrow(mem) = &mut raw.body else {
79        log::warn!("invalid message: {raw:?}");
80        return;
81    };
82
83    let msg = M::from(SimpleMemoryMessage::from(&*mem));
84    let (arg1, arg2) = handler.handle(msg, raw.sender.pid().unwrap(), context).to_usize_pair();
85    mem.offset = xous::MemoryAddress::new(arg1);
86    mem.valid = xous::MemoryAddress::new(arg2);
87}
88
89/// Send a [`LendMut`] message.
90pub fn lend_mut<M: LendMut>(cid: xous::CID, msg: M) -> M::Response {
91    let msg: SimpleMemoryMessage = msg.into();
92    let result = xous::send_message(
93        cid,
94        xous::Message::MutableBorrow(xous::MemoryMessage {
95            id: M::ID,
96            buf: msg.buf,
97            offset: xous::MemoryAddress::new(msg.arg1),
98            valid: xous::MemoryAddress::new(msg.arg2),
99        }),
100    );
101    match result {
102        Ok(xous::Result::MemoryReturned(_range, arg1, arg2)) => M::Response::from_usize_pair(
103            arg1.map(|v| v.get()).unwrap_or_default(),
104            arg2.map(|v| v.get()).unwrap_or_default(),
105        ),
106        _ => panic!("Unexpected return from send_message: {result:?}"),
107    }
108}