Skip to main content

corevm_guest/input/
service_messages.rs

1//! Inter-service messages.
2
3#![allow(clippy::missing_safety_doc)]
4
5use crate::c;
6use core::mem::size_of_val;
7use corevm_types::{flags::RecvMessage, GuestId, RecvMessageOutcome};
8
9/// Pop the next service message from the incoming messages queue.
10///
11/// Returns `None` if the queue is empty.
12///
13/// This is a non-blocking variant of [`recv_message`].
14#[cfg(feature = "alloc")]
15pub fn try_recv_message() -> Option<(alloc::vec::Vec<u8>, GuestId)> {
16	let ret = unsafe { c::recv_message(0, 0, RecvMessage::NON_BLOCKING.bits()) };
17	let (len, source) = RecvMessageOutcome::from_reg(ret).into_inner()?;
18	let mut buf = alloc::vec::Vec::with_capacity(len as usize);
19	unsafe {
20		c::recv_message(buf.as_mut_ptr() as u64, u64::from(len), RecvMessage::NON_BLOCKING.bits())
21	};
22	unsafe { buf.set_len(len as usize) };
23	Some((buf, source))
24}
25
26/// Pop the next service message from the incoming messages queue into the supplied buffer.
27///
28/// Returns `None` if the queue is empty.
29/// Returns `Some(Err(n))` where `n` is the message size if the buffer is too small.
30/// On success returns `Some(Ok(n))` where `n` is the message size.
31///
32/// This is a non-blocking variant of [`recv_message_into`].
33#[inline]
34pub fn try_recv_message_into(buf: &mut [u8]) -> Option<Result<(usize, GuestId), usize>> {
35	let ret = unsafe {
36		c::recv_message(buf.as_mut_ptr() as u64, buf.len() as u64, RecvMessage::NON_BLOCKING.bits())
37	};
38	let (len, source) = RecvMessageOutcome::from_reg(ret).into_inner()?;
39	if len > buf.len() as u32 {
40		return Some(Err(len as usize));
41	}
42	Some(Ok((len as usize, source)))
43}
44
45/// Pop the next service message from the incoming messages queue into the supplied buffer.
46///
47/// If the buffer is too small, the message is silently discarded.
48///
49/// Returns `None` if the queue is empty.
50/// On success returns `Some(n)` where `n` is the message size.
51///
52/// This is a non-blocking variant of [`recv_bounded_message_into`].
53#[inline]
54pub fn try_recv_bounded_message_into(buf: &mut [u8]) -> Option<(usize, GuestId)> {
55	let ret = unsafe {
56		c::recv_message(
57			buf.as_mut_ptr() as u64,
58			buf.len() as u64,
59			RecvMessage::DISCARD.bits() | RecvMessage::NON_BLOCKING.bits(),
60		)
61	};
62	let (len, source) = RecvMessageOutcome::from_reg(ret).into_inner()?;
63	Some((len as usize, source))
64}
65
66/// Pop the next service message from the incoming messages queue.
67///
68/// Blocks execution if the queue is empty until new data arrives.
69/// For a non-blocking variant see [`try_recv_message`].
70#[cfg(feature = "alloc")]
71pub fn recv_message() -> (alloc::vec::Vec<u8>, GuestId) {
72	let ret = unsafe { c::recv_message(0, 0, 0) };
73	let (len, source) =
74		RecvMessageOutcome::from_reg(ret).into_inner().expect("The call is blocking");
75	let mut buf = alloc::vec::Vec::with_capacity(len as usize);
76	unsafe { c::recv_message(buf.as_mut_ptr() as u64, u64::from(len), 0) };
77	unsafe { buf.set_len(len as usize) };
78	(buf, source)
79}
80
81/// Pop the next service message from the incoming messages queue into the supplied buffer.
82///
83/// Blocks execution if the queue is empty until new data arrives.
84/// For a non-blocking variant see [`try_recv_message_into`].
85///
86/// Returns `Err(n)` where `n` is the message size if the buffer is too small.
87/// On success returns `Ok(n)` where `n` is the message size.
88#[inline]
89pub fn recv_message_into(buf: &mut [u8]) -> Result<(usize, GuestId), usize> {
90	let ret = unsafe { c::recv_message(buf.as_mut_ptr() as u64, buf.len() as u64, 0) };
91	let (len, source) =
92		RecvMessageOutcome::from_reg(ret).into_inner().expect("The call is blocking");
93	if len > buf.len() as u32 {
94		return Err(len as usize);
95	}
96	Ok((len as usize, source))
97}
98
99/// Pop the next service message from the incoming messages queue into the supplied buffer.
100///
101/// If the buffer is too small, the message is silently discarded.
102///
103/// Blocks execution if the queue is empty until new data arrives.
104/// For a non-blocking variant see [`try_recv_bounded_message_into`].
105///
106/// Returns the message size.
107#[inline]
108pub fn recv_bounded_message_into(buf: &mut [u8]) -> Option<(usize, GuestId)> {
109	let ret = unsafe {
110		c::recv_message(buf.as_mut_ptr() as u64, buf.len() as u64, RecvMessage::DISCARD.bits())
111	};
112	let (len, source) = RecvMessageOutcome::from_reg(ret).into_inner()?;
113	Some((len as usize, source))
114}
115
116/// Send the `message` to the CoreVM service with id `guest_id`.
117#[inline]
118pub fn send_message(guest_id: GuestId, message: &[u8]) {
119	let address = message.as_ptr() as u64;
120	let len = size_of_val(message) as u64;
121	unsafe { c::send_message(u64::from(guest_id), address, len) };
122}