use sidevm_env::{
messages::{AccountId, QueryRequest, SystemMessage},
InputChannel, OcallError,
};
use super::{ocall, ResourceId};
use scale::{Decode, Error as CodecError};
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
use lazy_static::lazy_static;
pub struct Query {
pub origin: Option<AccountId>,
pub payload: Vec<u8>,
pub reply_tx: OneshotSender,
}
pub type GeneralMessage = Vec<u8>;
pub struct OneshotSender {
res_id: ResourceId,
}
impl OneshotSender {
const fn new(res_id: ResourceId) -> Self {
Self { res_id }
}
pub fn send(self, data: &[u8]) -> Result<(), OcallError> {
ocall::oneshot_send(self.res_id.0, data)
}
}
pub struct Receiver<M> {
res_id: ResourceId,
_marker: std::marker::PhantomData<M>,
}
pub struct Next<'a, M> {
ch: &'a Receiver<M>,
}
impl<T> Receiver<T> {
pub const fn new(res_id: ResourceId) -> Self {
Self {
res_id,
_marker: std::marker::PhantomData,
}
}
pub fn next(&self) -> Next<T> {
Next { ch: self }
}
}
impl Future for Next<'_, GeneralMessage> {
type Output = Option<GeneralMessage>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let waker_id = crate::env::tasks::intern_waker(cx.waker().clone());
match ocall::poll(waker_id, self.ch.res_id.0) {
Ok(msg) => Poll::Ready(Some(msg)),
Err(OcallError::EndOfFile) => Poll::Ready(None), Err(OcallError::Pending) => Poll::Pending,
Err(err) => panic!("unexpected error: {:?}", err),
}
}
}
impl Future for Next<'_, SystemMessage> {
type Output = Option<Result<SystemMessage, CodecError>>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let waker_id = crate::env::tasks::intern_waker(cx.waker().clone());
match ocall::poll(waker_id, self.ch.res_id.0) {
Ok(msg) => Poll::Ready(Some(SystemMessage::decode(&mut &msg[..]))),
Err(OcallError::EndOfFile) => Poll::Ready(None), Err(OcallError::Pending) => Poll::Pending,
Err(err) => panic!("unexpected error: {:?}", err),
}
}
}
impl Future for Next<'_, Query> {
type Output = Option<Query>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let waker_id = crate::env::tasks::intern_waker(cx.waker().clone());
match ocall::poll(waker_id, self.ch.res_id.0) {
Ok(msg) => {
let request =
QueryRequest::decode(&mut &msg[..]).expect("Failed to decode QueryRequest");
let reply_tx = OneshotSender::new(ResourceId(request.reply_tx));
Poll::Ready(Some(Query {
origin: request.origin,
payload: request.payload,
reply_tx,
}))
}
Err(OcallError::EndOfFile) => Poll::Ready(None), Err(OcallError::Pending) => Poll::Pending,
Err(err) => panic!("unexpected error: {:?}", err),
}
}
}
macro_rules! singleton_channel {
($ch: ident) => {{
lazy_static! {
static ref RX: Receiver<$ch> = {
let res_id = ocall::create_input_channel(InputChannel::$ch)
.expect("Failed to create input channel");
Receiver::new(ResourceId(res_id))
};
}
&*RX
}};
}
pub fn input_messages() -> &'static Receiver<GeneralMessage> {
singleton_channel!(GeneralMessage)
}
pub fn incoming_system_messages() -> &'static Receiver<SystemMessage> {
singleton_channel!(SystemMessage)
}
pub fn incoming_queries() -> &'static Receiver<Query> {
singleton_channel!(Query)
}