use crate::{
syscall::{
self,
CreateChannelError,
GetMessageError,
RegisterServiceError,
SendMessageError,
SubscribeToServiceError,
CHANNEL_MAX_NUM_HANDLES,
},
Handle,
};
use core::{future::Future, marker::PhantomData, mem, task::Poll};
use ptah::{DeserializeOwned, Serialize};
#[derive(Debug)]
pub enum ChannelSendError {
FailedToSerialize(ptah::ser::Error),
SendError(SendMessageError),
}
#[derive(Debug)]
pub enum ChannelReceiveError {
FailedToDeserialize(ptah::de::Error),
ReceiveError(GetMessageError),
}
pub struct Channel<S, R>(Handle, PhantomData<(S, R)>)
where
S: Serialize + DeserializeOwned,
R: Serialize + DeserializeOwned;
impl<S, R> Channel<S, R>
where
S: Serialize + DeserializeOwned,
R: Serialize + DeserializeOwned,
{
pub fn new_from_handle(handle: Handle) -> Channel<S, R> {
Channel(handle, PhantomData)
}
pub fn create() -> Result<(Channel<S, R>, Handle), CreateChannelError> {
let (this_end, other_end) = syscall::create_channel()?;
Ok((Self::new_from_handle(this_end), other_end))
}
pub fn subscribe_to_service(name: &str) -> Result<Channel<S, R>, SubscribeToServiceError> {
let handle = syscall::subscribe_to_service(name)?;
Ok(Self::new_from_handle(handle))
}
pub fn send(&self, message: &S) -> Result<(), ChannelSendError> {
let mut writer = ChannelWriter::new();
ptah::to_wire(message, &mut writer).map_err(|err| ChannelSendError::FailedToSerialize(err))?;
syscall::send_message(self.0, writer.bytes(), writer.handles())
.map_err(|err| ChannelSendError::SendError(err))
}
pub fn try_receive(&self) -> Result<Option<R>, ChannelReceiveError> {
let mut byte_buffer = [0u8; BYTES_BUFFER_SIZE];
let mut handle_buffer = [Handle::ZERO; CHANNEL_MAX_NUM_HANDLES];
match syscall::get_message(self.0, &mut byte_buffer, &mut handle_buffer) {
Ok((bytes, handles)) => {
let ptah_handles: &[u32] = unsafe { mem::transmute(handles) };
let message: R = ptah::from_wire(bytes, ptah_handles)
.map_err(|err| ChannelReceiveError::FailedToDeserialize(err))?;
Ok(Some(message))
}
Err(GetMessageError::NoMessage) => Ok(None),
Err(err) => Err(ChannelReceiveError::ReceiveError(err)),
}
}
pub fn receive(&self) -> impl Future<Output = Result<R, ChannelReceiveError>> + '_ {
core::future::poll_fn(|context| {
let mut byte_buffer = [0u8; BYTES_BUFFER_SIZE];
let mut handle_buffer = [Handle::ZERO; CHANNEL_MAX_NUM_HANDLES];
match syscall::get_message(self.0, &mut byte_buffer, &mut handle_buffer) {
Ok((bytes, handles)) => {
let ptah_handles: &[u32] = unsafe { mem::transmute(handles) };
let message: R = ptah::from_wire(bytes, ptah_handles)
.map_err(|err| ChannelReceiveError::FailedToDeserialize(err))?;
Poll::Ready(Ok(message))
}
Err(GetMessageError::NoMessage) => {
crate::rt::RUNTIME.get().reactor.lock().register(self.0, context.waker().clone());
Poll::Pending
}
Err(err) => Poll::Ready(Err(ChannelReceiveError::ReceiveError(err))),
}
})
}
}
impl Channel<!, Handle> {
pub fn register_service(name: &str) -> Result<Channel<!, Handle>, RegisterServiceError> {
Ok(Self::new_from_handle(syscall::register_service(name)?))
}
}
const BYTES_BUFFER_SIZE: usize = 512;
struct ChannelWriter {
byte_buffer: [u8; BYTES_BUFFER_SIZE],
handle_buffer: [Handle; CHANNEL_MAX_NUM_HANDLES],
num_bytes: usize,
num_handles: u8,
}
impl ChannelWriter {
pub fn new() -> ChannelWriter {
ChannelWriter {
byte_buffer: [0u8; BYTES_BUFFER_SIZE],
handle_buffer: [Handle::ZERO; CHANNEL_MAX_NUM_HANDLES],
num_bytes: 0,
num_handles: 0,
}
}
pub fn bytes(&self) -> &[u8] {
&self.byte_buffer[0..self.num_bytes]
}
pub fn handles(&self) -> &[Handle] {
&self.handle_buffer[0..(self.num_handles as usize)]
}
}
impl<'a> ptah::Writer for &'a mut ChannelWriter {
fn write(&mut self, buf: &[u8]) -> ptah::ser::Result<()> {
if (self.num_bytes + buf.len()) > BYTES_BUFFER_SIZE {
return Err(ptah::ser::Error::WriterFullOfBytes);
}
self.byte_buffer[self.num_bytes..(self.num_bytes + buf.len())].copy_from_slice(buf);
self.num_bytes += buf.len();
Ok(())
}
fn push_handle(&mut self, handle: ptah::Handle) -> ptah::ser::Result<ptah::HandleSlot> {
if (self.num_handles as usize + 1) > CHANNEL_MAX_NUM_HANDLES {
return Err(ptah::ser::Error::WriterFullOfHandles);
}
self.handle_buffer[self.num_handles as usize] = Handle(handle);
let slot = ptah::make_handle_slot(self.num_handles);
self.num_handles += 1;
Ok(slot)
}
}