use std::future::Future;
use std::pin::Pin;
use serde_json::Value;
pub type SyscallFuture = Pin<Box<dyn Future<Output = Result<Value, SyscallError>> + Send>>;
pub type FetchFuture = Pin<Box<dyn Future<Output = Result<FetchResponse, SyscallError>> + Send>>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FetchRequest {
pub url: String,
pub method: String,
pub headers: Vec<(String, String)>,
pub body: Option<Vec<u8>>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FetchResponse {
pub status: u16,
pub headers: Vec<(String, String)>,
pub body: Vec<u8>,
}
pub trait Syscall: Send + Sync {
fn call(&self, args: Value) -> SyscallFuture;
}
impl<F, Fut> Syscall for F
where
F: Fn(Value) -> Fut + Send + Sync,
Fut: Future<Output = Result<Value, SyscallError>> + Send + 'static,
{
fn call(&self, args: Value) -> SyscallFuture {
Box::pin(self(args))
}
}
pub trait Fetch: Send + Sync {
fn fetch(&self, request: FetchRequest) -> FetchFuture;
}
impl<F, Fut> Fetch for F
where
F: Fn(FetchRequest) -> Fut + Send + Sync,
Fut: Future<Output = Result<FetchResponse, SyscallError>> + Send + 'static,
{
fn fetch(&self, request: FetchRequest) -> FetchFuture {
Box::pin(self(request))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SyscallError {
pub message: String,
pub code: Option<String>,
}
impl SyscallError {
pub fn new(message: impl Into<String>) -> Self {
Self {
message: message.into(),
code: None,
}
}
pub fn with_code(mut self, code: impl Into<String>) -> Self {
self.code = Some(code.into());
self
}
}
impl std::fmt::Display for SyscallError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.message)
}
}
impl std::error::Error for SyscallError {}