Skip to main content
KeyOS API Reference

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::{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(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 = 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 init: AsyncMessageInit<[u32; 4]> = crate::Buffer::deserialize(mem).whence()?;
232            let AsyncMessageInit { cid, msg_id, msg } = init;
233            let request = BlockingScalarResponse {
234                responder: Some(Responder::Async { cid, msg_id }),
235                pid,
236                default: S::default_response,
237                response: None,
238            };
239            let request = BlockingScalarRequest { message: M::from_scalar(msg), response: request };
240            handler.handle(request, context);
241            Ok(())
242        }
243        _ => Err(rancor::Error::new(WrongMessageTypeError)).whence(),
244    }
245}
246
247/// decode async response from raw envelope
248pub fn decode_scalar_async_response<R>(raw: xous::MessageEnvelope) -> R
249where
250    R: ScalarCodec,
251{
252    try_decode_scalar_async_response(raw).unwrap()
253}
254
255/// try to decode async response from raw envelope, returns error instead of panic
256pub fn try_decode_scalar_async_response<R>(mut raw: xous::MessageEnvelope) -> whence::Result<R, crate::Error>
257where
258    R: ScalarCodec,
259{
260    let scalar = extract_scalar_message(&mut raw).whence()?;
261    Ok(R::from_scalar(scalar))
262}
263
264// ==================== fire-and-forget ====================
265
266/// stack allocated message with no response
267pub trait Scalar: ScalarCodec + crate::MessageId {
268    fn to_message(&self) -> xous::ScalarMessage
269    where
270        Self: Sized,
271    {
272        scalar_to_message(self, Self::ID)
273    }
274}
275
276/// handle fire-and-forget scalar messages
277pub trait ScalarHandler<M>
278where
279    M: Scalar,
280    Self: Server,
281{
282    /// process message, no response expected
283    fn handle(&mut self, msg: M, sender: xous::PID, context: &mut ServerContext<Self>);
284}
285
286/// Send a [`Scalar`] message. Blocks if queues are full.
287///
288/// Warning: Cannot be used in an IRQ handle
289pub fn send_scalar<M>(cid: xous::CID, msg: M)
290where
291    M: Scalar,
292{
293    try_send_scalar(cid, msg).unwrap()
294}
295
296/// Send a [`Scalar`] message. Blocks if queues are full.
297///
298/// Warning: Cannot be used in an IRQ handle
299pub fn try_send_scalar<M>(cid: xous::CID, msg: M) -> whence::Result<(), xous::Error>
300where
301    M: Scalar,
302{
303    let msg = xous::Message::Scalar(msg.to_message());
304    xous::send_message(cid, msg).whence()?;
305    Ok(())
306}
307
308/// Try sending a [`Scalar`] message, return error if the syscall queue is full.
309/// Can be used in an IRQ handler.
310pub fn send_scalar_nowait<M>(cid: xous::CID, msg: M) -> whence::Result<(), xous::Error>
311where
312    M: Scalar,
313{
314    let msg = xous::Message::Scalar(msg.to_message());
315    xous::try_send_message(cid, msg).whence()?;
316    Ok(())
317}
318
319/// Message handler, used by ServerMessages::messages()
320pub fn handle_scalar_message<M, S>(
321    handler: &mut S,
322    mut raw: xous::MessageEnvelope,
323    context: &mut ServerContext<S>,
324) where
325    M: Scalar,
326    S: ScalarHandler<M>,
327{
328    let pid = raw.sender.pid().unwrap();
329
330    match &mut raw.body {
331        xous::Message::Scalar(scalar) => {
332            let message = scalar_from_message(scalar);
333            handler.handle(message, pid, context);
334        }
335        _ => {
336            log::error!("invalid Scalar message {} (ID {}) from PID {pid}: {raw:?}", type_name::<M>(), M::ID,);
337        }
338    }
339}
340
341// ==================== internal ====================
342
343// internal: handle async responses
344pub(crate) fn scalar_async_response_handler<M, S>(
345    handler: &mut S,
346    raw: xous::MessageEnvelope,
347    context: &mut ServerContext<S>,
348) where
349    M: BlockingScalar,
350    S: BlockingScalarResponseHandler<M::Response>,
351{
352    let msg_id = raw.id();
353    let sender = raw.sender.pid().unwrap();
354
355    match try_decode_scalar_async_response(raw) {
356        Ok(response) => {
357            handler.handle_response(response, sender, context);
358        }
359        Err(e) => log::warn!("invalid async scalar response {e}"),
360    }
361
362    context.remove_handler(msg_id);
363}
364
365#[derive(Debug)]
366enum Responder {
367    /// response returned via return_scalar5 (blocking call)
368    Sync(xous::MessageEnvelope),
369    /// response sent as new scalar message (async call)
370    Async { cid: xous::CID, msg_id: xous::MessageId },
371}
372
373impl Responder {
374    fn respond<R>(self, response: R) -> whence::Result<(), xous::Error>
375    where
376        R: ScalarCodec,
377    {
378        match self {
379            Responder::Sync(envelope) => {
380                let [arg1, arg2, arg3, arg4] = response.as_scalar().map(|a| a as usize);
381                xous::return_scalar5(envelope.sender, arg1, arg2, arg3, arg4, 0).whence()
382            }
383            Responder::Async { cid, msg_id } => {
384                let _disconnect = defer::defer(|| {
385                    xous::disconnect(cid).ok();
386                });
387                let msg = scalar_to_message(&response, msg_id);
388                xous::try_send_message(cid, xous::Message::Scalar(msg)).whence()?;
389                Ok(())
390            }
391        }
392    }
393}
394
395// ==================== codec ====================
396
397pub use codec::*;
398
399mod codec {
400    use xous::MemoryRange;
401
402    // ==================== trait definitions ====================
403
404    pub trait FromScalar<const N: usize> {
405        fn from_scalar(value: [u32; N]) -> Self;
406    }
407
408    pub trait AsScalar<const N: usize> {
409        fn as_scalar(&self) -> [u32; N];
410    }
411
412    // ==================== blanket impls ====================
413
414    impl<T: FromScalar<3>> FromScalar<4> for T {
415        fn from_scalar(value: [u32; 4]) -> Self { Self::from_scalar([value[0], value[1], value[2]]) }
416    }
417
418    impl<T: AsScalar<3>> AsScalar<4> for T {
419        fn as_scalar(&self) -> [u32; 4] {
420            let s = Self::as_scalar(self);
421            [s[0], s[1], s[2], 0]
422        }
423    }
424
425    impl<T: FromScalar<2>> FromScalar<3> for T {
426        fn from_scalar(value: [u32; 3]) -> Self { Self::from_scalar([value[0], value[1]]) }
427    }
428
429    impl<T: AsScalar<2>> AsScalar<3> for T {
430        fn as_scalar(&self) -> [u32; 3] {
431            let s = Self::as_scalar(self);
432            [s[0], s[1], 0]
433        }
434    }
435
436    impl<T: FromScalar<1>> FromScalar<2> for T {
437        fn from_scalar(value: [u32; 2]) -> Self { Self::from_scalar([value[0]]) }
438    }
439
440    impl<T: AsScalar<1>> AsScalar<2> for T {
441        fn as_scalar(&self) -> [u32; 2] {
442            let s = Self::as_scalar(self);
443            [s[0], 0]
444        }
445    }
446
447    // ==================== primitive types ====================
448
449    impl FromScalar<1> for () {
450        fn from_scalar(_value: [u32; 1]) -> Self {}
451    }
452
453    impl AsScalar<1> for () {
454        fn as_scalar(&self) -> [u32; 1] { [0] }
455    }
456
457    impl FromScalar<1> for usize {
458        fn from_scalar(value: [u32; 1]) -> Self { value[0] as usize }
459    }
460
461    impl AsScalar<1> for usize {
462        fn as_scalar(&self) -> [u32; 1] { [*self as u32] }
463    }
464
465    impl FromScalar<1> for i32 {
466        fn from_scalar(value: [u32; 1]) -> Self { value[0] as i32 }
467    }
468
469    impl AsScalar<1> for i32 {
470        fn as_scalar(&self) -> [u32; 1] { [*self as u32] }
471    }
472
473    impl FromScalar<1> for u8 {
474        fn from_scalar(value: [u32; 1]) -> Self { value[0] as u8 }
475    }
476
477    impl AsScalar<1> for u8 {
478        fn as_scalar(&self) -> [u32; 1] { [*self as u32] }
479    }
480
481    impl FromScalar<1> for u16 {
482        fn from_scalar(value: [u32; 1]) -> Self { value[0] as u16 }
483    }
484
485    impl AsScalar<1> for u16 {
486        fn as_scalar(&self) -> [u32; 1] { [*self as u32] }
487    }
488
489    impl FromScalar<1> for u32 {
490        fn from_scalar(value: [u32; 1]) -> Self { value[0] }
491    }
492
493    impl AsScalar<1> for u32 {
494        fn as_scalar(&self) -> [u32; 1] { [*self] }
495    }
496
497    impl FromScalar<2> for u64 {
498        fn from_scalar(value: [u32; 2]) -> Self { (value[0] as u64) | ((value[1] as u64) << 32) }
499    }
500
501    impl AsScalar<2> for u64 {
502        fn as_scalar(&self) -> [u32; 2] { [*self as u32, (*self >> 32) as u32] }
503    }
504
505    impl FromScalar<1> for bool {
506        fn from_scalar(value: [u32; 1]) -> Self { value[0] != 0 }
507    }
508
509    impl AsScalar<1> for bool {
510        fn as_scalar(&self) -> [u32; 1] { [if *self { 1 } else { 0 }] }
511    }
512
513    // ==================== xous types ====================
514
515    impl FromScalar<1> for xous::PID {
516        fn from_scalar(value: [u32; 1]) -> Self { xous::PID::new(value[0].try_into().unwrap()).unwrap() }
517    }
518
519    impl AsScalar<1> for xous::PID {
520        fn as_scalar(&self) -> [u32; 1] { [self.get() as u32] }
521    }
522
523    impl AsScalar<4> for xous::SID {
524        fn as_scalar(&self) -> [u32; 4] {
525            let s = self.to_u32();
526            [s.0, s.1, s.2, s.3]
527        }
528    }
529
530    impl FromScalar<4> for xous::SID {
531        fn from_scalar(value: [u32; 4]) -> Self { Self::from_u32(value[0], value[1], value[2], value[3]) }
532    }
533
534    impl FromScalar<4> for xous::AppId {
535        fn from_scalar(value: [u32; 4]) -> Self { value.into() }
536    }
537
538    impl AsScalar<4> for xous::AppId {
539        fn as_scalar(&self) -> [u32; 4] { self.into() }
540    }
541
542    // ==================== memory range (platform specific) ====================
543
544    #[cfg(not(keyos))]
545    impl AsScalar<3> for MemoryRange {
546        fn as_scalar(&self) -> [u32; 3] {
547            let ptr = self.as_ptr() as usize;
548            [ptr as _, (ptr >> 32) as _, self.len() as _]
549        }
550    }
551
552    #[cfg(not(keyos))]
553    impl FromScalar<3> for MemoryRange {
554        fn from_scalar(value: [u32; 3]) -> Self {
555            let ptr = (value[0] as usize) | ((value[1] as usize) << 32);
556            unsafe { MemoryRange::new(ptr, value[2] as _).expect("valid memory range") }
557        }
558    }
559
560    #[cfg(keyos)]
561    impl AsScalar<2> for MemoryRange {
562        fn as_scalar(&self) -> [u32; 2] { [self.as_ptr() as _, self.len() as _] }
563    }
564
565    #[cfg(keyos)]
566    impl FromScalar<2> for MemoryRange {
567        fn from_scalar(value: [u32; 2]) -> Self {
568            unsafe { MemoryRange::new(value[0] as _, value[1] as _).expect("valid memory range") }
569        }
570    }
571
572    // ==================== complex types ====================
573
574    impl<T: FromScalar<3>> FromScalar<4> for Option<T> {
575        fn from_scalar(value: [u32; 4]) -> Self {
576            if value[0] == 1 {
577                Some(T::from_scalar([value[1], value[2], value[3]]))
578            } else {
579                None
580            }
581        }
582    }
583
584    impl<T: AsScalar<3>> AsScalar<4> for Option<T> {
585        fn as_scalar(&self) -> [u32; 4] {
586            match self {
587                Some(value) => {
588                    let s = value.as_scalar();
589                    [1, s[0], s[1], s[2]]
590                }
591                None => [0, 0, 0, 0],
592            }
593        }
594    }
595
596    impl<T: FromScalar<3>, E: FromScalar<3>> FromScalar<4> for Result<T, E> {
597        fn from_scalar(value: [u32; 4]) -> Self {
598            if value[0] == 1 {
599                Ok(T::from_scalar([value[1], value[2], value[3]]))
600            } else {
601                Err(E::from_scalar([value[1], value[2], value[3]]))
602            }
603        }
604    }
605
606    impl<T: AsScalar<3>, E: AsScalar<3>> AsScalar<4> for Result<T, E> {
607        fn as_scalar(&self) -> [u32; 4] {
608            match self {
609                Ok(value) => {
610                    let s = value.as_scalar();
611                    [1, s[0], s[1], s[2]]
612                }
613                Err(err) => {
614                    let s = err.as_scalar();
615                    [0, s[0], s[1], s[2]]
616                }
617            }
618        }
619    }
620}
621
622#[inline]
623pub(crate) fn extract_scalar_message(
624    raw: &mut xous::MessageEnvelope,
625) -> core::result::Result<[u32; 4], rkyv::rancor::Error> {
626    match &mut raw.body {
627        xous::Message::Scalar(scalar) => {
628            let [_, arg1, arg2, arg3, arg4] = scalar.to_usize().map(|a| a as u32);
629            Ok([arg1, arg2, arg3, arg4])
630        }
631        _ => rkyv::rancor::fail!(crate::WrongMessageTypeError),
632    }
633}
634
635#[inline]
636pub(crate) fn scalar_to_message(s: &impl crate::AsScalar<4>, msg_id: usize) -> xous::ScalarMessage {
637    let [arg1, arg2, arg3, arg4] = s.as_scalar().map(|a| a as usize);
638    xous::ScalarMessage { id: msg_id, arg1, arg2, arg3, arg4 }
639}
640
641#[inline]
642pub(crate) fn scalar_from_message<M: crate::FromScalar<4>>(msg: &xous::ScalarMessage) -> M {
643    let [_, arg1, arg2, arg3, arg4] = msg.to_usize().map(|a| a as u32);
644    M::from_scalar([arg1, arg2, arg3, arg4])
645}