use pink_sidevm_env::{
query::{AccountId, QueryRequest},
OcallError,
};
use super::{ocall, ResourceId};
use scale::Decode;
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
pub struct Query {
pub origin: Option<AccountId>,
pub payload: Vec<u8>,
pub reply_tx: OneshotSender,
}
pub type Message = 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<'_, Message> {
type Output = Option<Message>;
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<'_, 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),
}
}
}
pub fn input_messages() -> &'static Receiver<Message> {
static MSG_RX: Receiver<Message> = Receiver::new(ResourceId(0));
&MSG_RX
}
pub fn incoming_queries() -> &'static Receiver<Query> {
static QUERY_RX: Receiver<Query> = Receiver::new(ResourceId(1));
&QUERY_RX
}