server/
scalar.rs

1// SPDX-FileCopyrightText: 2025 Foundation Devices, Inc. <hello@foundation.xyz>
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4//! scalar message for server IPC
5
6use std::any::type_name;
7
8use rkyv::rancor::{self, Source as _};
9use whence::WhenceExt;
10
11use crate::{utils, AsyncMessageInit, Error, Server, ServerContext, WrongMessageTypeError};
12
13// ==================== core ====================
14
15/// stack allocated message that expects a response
16pub trait BlockingScalar
17where
18    Self: ScalarCodec,
19    Self: crate::MessageId,
20{
21    /// response type for this message
22    type Response: ScalarCodec;
23}
24
25/// encoding requirements for scalar messages
26pub trait ScalarCodec
27where
28    Self: FromScalar<4> + AsScalar<4>,
29{
30}
31
32impl<T> ScalarCodec for T where T: FromScalar<4> + AsScalar<4> {}
33
34// ==================== handler traits ====================
35
36/// handle scalar messages synchronously
37pub trait BlockingScalarHandler<M>
38where
39    M: BlockingScalar,
40    Self: Server,
41{
42    /// process message and return response immediately
43    fn handle(&mut self, msg: M, sender: xous::PID, context: &mut ServerContext<Self>) -> M::Response;
44}
45
46/// handle scalar messages asynchronously (can defer response)
47pub trait BlockingScalarAsyncHandler<M>
48where
49    M: BlockingScalar,
50    Self: Server,
51{
52    /// process message, response can be sent later
53    fn handle(&mut self, request: BlockingScalarRequest<M>, context: &mut ServerContext<Self>);
54    /// default response if handler drops without responding
55    fn default_response() -> M::Response;
56}
57
58// auto-convert sync handlers to async
59impl<T, M> BlockingScalarAsyncHandler<M> for T
60where
61    M: BlockingScalar,
62    T: BlockingScalarHandler<M>,
63{
64    fn handle(&mut self, request: BlockingScalarRequest<M>, context: &mut ServerContext<Self>) {
65        let BlockingScalarRequest { message, response: request } = request;
66        let response = <Self as BlockingScalarHandler<M>>::handle(self, message, request.pid(), context);
67        if let Err(e) = request.respond(response) {
68            log::warn!("failed to respond scalar {e:?}");
69        }
70    }
71
72    fn default_response() -> <M as BlockingScalar>::Response {
73        unreachable!("default value not required in sync handler")
74    }
75}
76
77/// handle async responses from other servers
78pub trait BlockingScalarResponseHandler<R>
79where
80    Self: Server,
81    R: ScalarCodec,
82{
83    /// process received async response
84    fn handle_response(&mut self, response: R, sender: xous::PID, context: &mut ServerContext<Self>);
85}
86
87// ==================== types ====================
88
89/// scalar request with deferred response capability
90#[derive(Debug)]
91pub struct BlockingScalarRequest<M: BlockingScalar> {
92    pub message: M,
93    pub response: BlockingScalarResponse<M::Response>,
94}
95
96/// deferred response that sends default on drop if not used
97#[derive(Debug)]
98pub struct BlockingScalarResponse<R: ScalarCodec> {
99    responder: Option<Responder>,
100    pid: xous::PID,
101    default: fn() -> R,
102    response: Option<R>,
103}
104
105impl<R: ScalarCodec> BlockingScalarResponse<R> {
106    /// get sender's process ID
107    pub fn pid(&self) -> xous::PID { self.pid }
108
109    /// send response
110    pub fn respond(mut self, response: R) -> whence::Result<(), xous::Error> {
111        let responder = self.responder.take().unwrap();
112        responder.respond(response)
113    }
114
115    /// set response
116    /// will be sent on drop if [`Self::respond`] is not called
117    pub fn set_response(&mut self, response: R) { self.response = Some(response) }
118}
119
120// auto-send default response on drop
121impl<R: ScalarCodec> Drop for BlockingScalarResponse<R> {
122    fn drop(&mut self) {
123        if let Some(responder) = self.responder.take() {
124            let default = self.response.take().unwrap_or_else(self.default);
125            responder.respond(default).ok();
126        }
127    }
128}
129
130// ==================== API ====================
131
132/// send scalar message and block for response
133pub fn send_blocking_scalar<M>(cid: xous::CID, msg: M) -> M::Response
134where
135    M: BlockingScalar,
136{
137    try_send_blocking_scalar(cid, msg).unwrap()
138}
139
140/// send scalar message, returns error instead of panic
141pub fn try_send_blocking_scalar<M>(cid: xous::CID, msg: M) -> whence::Result<M::Response, xous::Error>
142where
143    M: BlockingScalar,
144{
145    let msg = xous::Message::BlockingScalar(utils::scalar_to_message(&msg, M::ID));
146    let result = xous::send_message(cid, msg).whence()?;
147    match result {
148        xous::Result::Scalar5(arg1, arg2, arg3, arg4, _) => {
149            Ok(M::Response::from_scalar([arg1 as u32, arg2 as u32, arg3 as u32, arg4 as u32]))
150        }
151        unexpected => {
152            log::error!(
153                "unexpected result for message {} (ID {}): {:?}",
154                type_name::<M>(),
155                M::ID,
156                unexpected
157            );
158            Err(xous::Error::InternalError).whence()?
159        }
160    }
161}
162
163/// send scalar message without blocking
164/// returns the [`xous::MessageId`] used for the reply
165pub fn send_scalar_async<M>(cid: xous::CID, msg: M, sid: xous::SID) -> xous::MessageId
166where
167    M: BlockingScalar,
168{
169    try_send_scalar_async(cid, msg, sid).unwrap()
170}
171
172/// send async scalar message, returns error instead of panic
173/// returns the [`xous::MessageId`] used for the reply
174pub fn try_send_scalar_async<M>(
175    cid: xous::CID,
176    msg: M,
177    sid: xous::SID,
178) -> whence::Result<xous::MessageId, crate::Error>
179where
180    M: BlockingScalar,
181{
182    let msg_id = crate::next_dynamic_message_id();
183    let pid = xous::get_remote_pid(cid).whence()?;
184    let cid_remote = xous::connect_for_process(pid, sid).whence()?;
185    xous::allow_messages_on_connection(pid, cid_remote, msg_id..(msg_id + 1)).whence()?;
186    AsyncMessageInit { cid: cid_remote, msg_id, msg }.send_scalar(cid)?;
187    Ok(msg_id)
188}
189
190/// Message handler, used by ServerMessages::messages()
191pub fn handle_blocking_scalar_message<M, S>(
192    handler: &mut S,
193    raw: xous::MessageEnvelope,
194    context: &mut ServerContext<S>,
195) where
196    M: BlockingScalar,
197    S: BlockingScalarAsyncHandler<M>,
198{
199    let pid = raw.sender.pid().unwrap();
200    if let Err(e) = try_handle_blocking_scalar_message(pid, handler, raw, context) {
201        log::warn!("blocking scalar handle error (PID {pid}) for {}: {e}", type_name::<M>());
202    }
203}
204
205fn try_handle_blocking_scalar_message<M, S>(
206    pid: xous::PID,
207    handler: &mut S,
208    mut raw: xous::MessageEnvelope,
209    context: &mut ServerContext<S>,
210) -> whence::Result<(), Error>
211where
212    M: BlockingScalar,
213    S: BlockingScalarAsyncHandler<M>,
214{
215    match &mut raw.body {
216        xous::Message::BlockingScalar(scalar) => {
217            // sync case - extract message and create request
218            let message = utils::scalar_from_message::<M>(scalar);
219            let request = BlockingScalarResponse {
220                responder: Some(Responder::Sync(raw)),
221                pid,
222                default: S::default_response,
223                response: None,
224            };
225            let request = BlockingScalarRequest { message, response: request };
226            handler.handle(request, context);
227            Ok(())
228        }
229        xous::Message::Move(mem) => {
230            // async case - extract async wrapper
231            let buf = unsafe { xous_ipc::Buffer::from_memory_message(mem) };
232            let init: AsyncMessageInit<[u32; 4]> = buf.to_original().whence()?;
233            let AsyncMessageInit { cid, msg_id, msg } = init;
234            let request = BlockingScalarResponse {
235                responder: Some(Responder::Async { cid, msg_id }),
236                pid,
237                default: S::default_response,
238                response: None,
239            };
240            let request = BlockingScalarRequest { message: M::from_scalar(msg), response: request };
241            handler.handle(request, context);
242            Ok(())
243        }
244        _ => Err(rancor::Error::new(WrongMessageTypeError)).whence(),
245    }
246}
247
248/// decode async response from raw envelope
249pub fn decode_scalar_async_response<R>(raw: xous::MessageEnvelope) -> R
250where
251    R: ScalarCodec,
252{
253    try_decode_scalar_async_response(raw).unwrap()
254}
255
256/// try to decode async response from raw envelope, returns error instead of panic
257pub fn try_decode_scalar_async_response<R>(mut raw: xous::MessageEnvelope) -> whence::Result<R, crate::Error>
258where
259    R: ScalarCodec,
260{
261    let scalar = utils::extract_scalar_message(&mut raw).whence()?;
262    Ok(R::from_scalar(scalar))
263}
264
265// ==================== fire-and-forget ====================
266
267/// stack allocated message with no response
268pub trait Scalar: ScalarCodec + crate::MessageId {
269    fn to_message(&self) -> xous::ScalarMessage
270    where
271        Self: Sized,
272    {
273        utils::scalar_to_message(self, Self::ID)
274    }
275}
276
277/// handle fire-and-forget scalar messages
278pub trait ScalarHandler<M>
279where
280    M: Scalar,
281    Self: Server,
282{
283    /// process message, no response expected
284    fn handle(&mut self, msg: M, sender: xous::PID, context: &mut ServerContext<Self>);
285}
286
287/// Send a [`Scalar`] message. Blocks if queues are full.
288///
289/// Warning: Cannot be used in an IRQ handle
290pub fn send_scalar<M>(cid: xous::CID, msg: M)
291where
292    M: Scalar,
293{
294    try_send_scalar(cid, msg).unwrap()
295}
296
297/// Send a [`Scalar`] message. Blocks if queues are full.
298///
299/// Warning: Cannot be used in an IRQ handle
300pub fn try_send_scalar<M>(cid: xous::CID, msg: M) -> whence::Result<(), xous::Error>
301where
302    M: Scalar,
303{
304    let msg = xous::Message::Scalar(msg.to_message());
305    xous::send_message(cid, msg).whence()?;
306    Ok(())
307}
308
309/// Try sending a [`Scalar`] message, return error if the syscall queue is full.
310/// Can be used in an IRQ handler.
311pub fn send_scalar_nowait<M>(cid: xous::CID, msg: M) -> whence::Result<(), xous::Error>
312where
313    M: Scalar,
314{
315    let msg = xous::Message::Scalar(msg.to_message());
316    xous::try_send_message(cid, msg).whence()?;
317    Ok(())
318}
319
320/// Message handler, used by ServerMessages::messages()
321pub fn handle_scalar_message<M, S>(
322    handler: &mut S,
323    mut raw: xous::MessageEnvelope,
324    context: &mut ServerContext<S>,
325) where
326    M: Scalar,
327    S: ScalarHandler<M>,
328{
329    let pid = raw.sender.pid().unwrap();
330
331    match &mut raw.body {
332        xous::Message::Scalar(scalar) => {
333            let message = utils::scalar_from_message(scalar);
334            handler.handle(message, pid, context);
335        }
336        _ => {
337            log::error!("invalid Scalar message {} (ID {}) from PID {pid}: {raw:?}", type_name::<M>(), M::ID,);
338        }
339    }
340}
341
342// ==================== internal ====================
343
344// internal: handle async responses
345pub(crate) fn scalar_async_response_handler<M, S>(
346    handler: &mut S,
347    raw: xous::MessageEnvelope,
348    context: &mut ServerContext<S>,
349) where
350    M: BlockingScalar,
351    S: BlockingScalarResponseHandler<M::Response>,
352{
353    let msg_id = raw.id();
354    let sender = raw.sender.pid().unwrap();
355
356    match try_decode_scalar_async_response(raw) {
357        Ok(response) => {
358            handler.handle_response(response, sender, context);
359        }
360        Err(e) => log::warn!("invalid async scalar response {e}"),
361    }
362
363    context.remove_handler(msg_id);
364}
365
366#[derive(Debug)]
367enum Responder {
368    /// response returned via return_scalar5 (blocking call)
369    Sync(xous::MessageEnvelope),
370    /// response sent as new scalar message (async call)
371    Async { cid: xous::CID, msg_id: xous::MessageId },
372}
373
374impl Responder {
375    fn respond<R>(self, response: R) -> whence::Result<(), xous::Error>
376    where
377        R: ScalarCodec,
378    {
379        match self {
380            Responder::Sync(envelope) => {
381                let [arg1, arg2, arg3, arg4] = response.as_scalar().map(|a| a as usize);
382                xous::return_scalar5(envelope.sender, arg1, arg2, arg3, arg4, 0).whence()
383            }
384            Responder::Async { cid, msg_id } => {
385                let _disconnect = defer::defer(|| {
386                    xous::disconnect(cid).ok();
387                });
388                let msg = utils::scalar_to_message(&response, msg_id);
389                xous::try_send_message(cid, xous::Message::Scalar(msg)).whence()?;
390                Ok(())
391            }
392        }
393    }
394}
395
396// ==================== codec ====================
397
398pub use codec::*;
399
400mod codec {
401    use xous::MemoryRange;
402
403    // ==================== trait definitions ====================
404
405    pub trait FromScalar<const N: usize> {
406        fn from_scalar(value: [u32; N]) -> Self;
407    }
408
409    pub trait AsScalar<const N: usize> {
410        fn as_scalar(&self) -> [u32; N];
411    }
412
413    // ==================== blanket impls ====================
414
415    impl<T: FromScalar<3>> FromScalar<4> for T {
416        fn from_scalar(value: [u32; 4]) -> Self { Self::from_scalar([value[0], value[1], value[2]]) }
417    }
418
419    impl<T: AsScalar<3>> AsScalar<4> for T {
420        fn as_scalar(&self) -> [u32; 4] {
421            let s = Self::as_scalar(self);
422            [s[0], s[1], s[2], 0]
423        }
424    }
425
426    impl<T: FromScalar<2>> FromScalar<3> for T {
427        fn from_scalar(value: [u32; 3]) -> Self { Self::from_scalar([value[0], value[1]]) }
428    }
429
430    impl<T: AsScalar<2>> AsScalar<3> for T {
431        fn as_scalar(&self) -> [u32; 3] {
432            let s = Self::as_scalar(self);
433            [s[0], s[1], 0]
434        }
435    }
436
437    impl<T: FromScalar<1>> FromScalar<2> for T {
438        fn from_scalar(value: [u32; 2]) -> Self { Self::from_scalar([value[0]]) }
439    }
440
441    impl<T: AsScalar<1>> AsScalar<2> for T {
442        fn as_scalar(&self) -> [u32; 2] {
443            let s = Self::as_scalar(self);
444            [s[0], 0]
445        }
446    }
447
448    // ==================== primitive types ====================
449
450    impl FromScalar<1> for () {
451        fn from_scalar(_value: [u32; 1]) -> Self {}
452    }
453
454    impl AsScalar<1> for () {
455        fn as_scalar(&self) -> [u32; 1] { [0] }
456    }
457
458    impl FromScalar<1> for usize {
459        fn from_scalar(value: [u32; 1]) -> Self { value[0] as usize }
460    }
461
462    impl AsScalar<1> for usize {
463        fn as_scalar(&self) -> [u32; 1] { [*self as u32] }
464    }
465
466    impl FromScalar<1> for i32 {
467        fn from_scalar(value: [u32; 1]) -> Self { value[0] as i32 }
468    }
469
470    impl AsScalar<1> for i32 {
471        fn as_scalar(&self) -> [u32; 1] { [*self as u32] }
472    }
473
474    impl FromScalar<1> for u8 {
475        fn from_scalar(value: [u32; 1]) -> Self { value[0] as u8 }
476    }
477
478    impl AsScalar<1> for u8 {
479        fn as_scalar(&self) -> [u32; 1] { [*self as u32] }
480    }
481
482    impl FromScalar<1> for u16 {
483        fn from_scalar(value: [u32; 1]) -> Self { value[0] as u16 }
484    }
485
486    impl AsScalar<1> for u16 {
487        fn as_scalar(&self) -> [u32; 1] { [*self as u32] }
488    }
489
490    impl FromScalar<1> for u32 {
491        fn from_scalar(value: [u32; 1]) -> Self { value[0] }
492    }
493
494    impl AsScalar<1> for u32 {
495        fn as_scalar(&self) -> [u32; 1] { [*self] }
496    }
497
498    impl FromScalar<2> for u64 {
499        fn from_scalar(value: [u32; 2]) -> Self { (value[0] as u64) | ((value[1] as u64) << 32) }
500    }
501
502    impl AsScalar<2> for u64 {
503        fn as_scalar(&self) -> [u32; 2] { [*self as u32, (*self >> 32) as u32] }
504    }
505
506    impl FromScalar<1> for bool {
507        fn from_scalar(value: [u32; 1]) -> Self { value[0] != 0 }
508    }
509
510    impl AsScalar<1> for bool {
511        fn as_scalar(&self) -> [u32; 1] { [if *self { 1 } else { 0 }] }
512    }
513
514    // ==================== xous types ====================
515
516    impl FromScalar<1> for xous::PID {
517        fn from_scalar(value: [u32; 1]) -> Self { xous::PID::new(value[0].try_into().unwrap()).unwrap() }
518    }
519
520    impl AsScalar<1> for xous::PID {
521        fn as_scalar(&self) -> [u32; 1] { [self.get() as u32] }
522    }
523
524    impl AsScalar<4> for xous::SID {
525        fn as_scalar(&self) -> [u32; 4] {
526            let s = self.to_u32();
527            [s.0, s.1, s.2, s.3]
528        }
529    }
530
531    impl FromScalar<4> for xous::SID {
532        fn from_scalar(value: [u32; 4]) -> Self { Self::from_u32(value[0], value[1], value[2], value[3]) }
533    }
534
535    impl FromScalar<4> for xous::AppId {
536        fn from_scalar(value: [u32; 4]) -> Self { value.into() }
537    }
538
539    impl AsScalar<4> for xous::AppId {
540        fn as_scalar(&self) -> [u32; 4] { self.into() }
541    }
542
543    // ==================== memory range (platform specific) ====================
544
545    #[cfg(not(keyos))]
546    impl AsScalar<3> for MemoryRange {
547        fn as_scalar(&self) -> [u32; 3] {
548            let ptr = self.as_ptr() as usize;
549            [ptr as _, (ptr >> 32) as _, self.len() as _]
550        }
551    }
552
553    #[cfg(not(keyos))]
554    impl FromScalar<3> for MemoryRange {
555        fn from_scalar(value: [u32; 3]) -> Self {
556            let ptr = (value[0] as usize) | ((value[1] as usize) << 32);
557            unsafe { MemoryRange::new(ptr, value[2] as _).expect("valid memory range") }
558        }
559    }
560
561    #[cfg(keyos)]
562    impl AsScalar<2> for MemoryRange {
563        fn as_scalar(&self) -> [u32; 2] { [self.as_ptr() as _, self.len() as _] }
564    }
565
566    #[cfg(keyos)]
567    impl FromScalar<2> for MemoryRange {
568        fn from_scalar(value: [u32; 2]) -> Self {
569            unsafe { MemoryRange::new(value[0] as _, value[1] as _).expect("valid memory range") }
570        }
571    }
572
573    // ==================== complex types ====================
574
575    impl<T: FromScalar<3>> FromScalar<4> for Option<T> {
576        fn from_scalar(value: [u32; 4]) -> Self {
577            if value[0] == 1 {
578                Some(T::from_scalar([value[1], value[2], value[3]]))
579            } else {
580                None
581            }
582        }
583    }
584
585    impl<T: AsScalar<3>> AsScalar<4> for Option<T> {
586        fn as_scalar(&self) -> [u32; 4] {
587            match self {
588                Some(value) => {
589                    let s = value.as_scalar();
590                    [1, s[0], s[1], s[2]]
591                }
592                None => [0, 0, 0, 0],
593            }
594        }
595    }
596
597    impl<T: FromScalar<3>, E: FromScalar<3>> FromScalar<4> for Result<T, E> {
598        fn from_scalar(value: [u32; 4]) -> Self {
599            if value[0] == 1 {
600                Ok(T::from_scalar([value[1], value[2], value[3]]))
601            } else {
602                Err(E::from_scalar([value[1], value[2], value[3]]))
603            }
604        }
605    }
606
607    impl<T: AsScalar<3>, E: AsScalar<3>> AsScalar<4> for Result<T, E> {
608        fn as_scalar(&self) -> [u32; 4] {
609            match self {
610                Ok(value) => {
611                    let s = value.as_scalar();
612                    [1, s[0], s[1], s[2]]
613                }
614                Err(err) => {
615                    let s = err.as_scalar();
616                    [0, s[0], s[1], s[2]]
617                }
618            }
619        }
620    }
621}