mod service_protocol;
mod vm;
use std::borrow::Cow;
use std::time::Duration;
pub use vm::CoreVM;
#[derive(Debug, Eq, PartialEq)]
pub struct Header {
pub key: Cow<'static, str>,
pub value: Cow<'static, str>,
}
#[derive(Debug)]
pub struct ResponseHead {
pub status_code: u16,
pub headers: Vec<Header>,
}
#[derive(Debug, Clone, Copy, thiserror::Error)]
#[error("Suspended execution")]
pub struct SuspendedError;
#[derive(Debug, Clone, thiserror::Error)]
#[error("VM Error [{code}]: {message}. Description: {description}")]
pub struct VMError {
pub code: u16,
pub message: Cow<'static, str>,
pub description: Cow<'static, str>,
}
impl VMError {
pub fn new(code: impl Into<u16>, message: impl Into<Cow<'static, str>>) -> Self {
VMError {
code: code.into(),
message: message.into(),
description: Default::default(),
}
}
}
#[derive(Debug, Clone, thiserror::Error)]
pub enum SuspendedOrVMError {
#[error(transparent)]
Suspended(SuspendedError),
#[error(transparent)]
VM(VMError),
}
#[derive(Debug, Eq, PartialEq)]
pub struct Input {
pub invocation_id: String,
pub random_seed: u64,
pub key: String,
pub headers: Vec<Header>,
pub input: Vec<u8>,
}
#[derive(Debug, Eq, PartialEq)]
pub struct Target {
pub service: String,
pub handler: String,
pub key: Option<String>,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct AsyncResultHandle(u32);
impl From<u32> for AsyncResultHandle {
fn from(value: u32) -> Self {
AsyncResultHandle(value)
}
}
impl From<AsyncResultHandle> for u32 {
fn from(value: AsyncResultHandle) -> Self {
value.0
}
}
#[derive(Debug, Eq, PartialEq)]
pub enum Value {
Void,
Success(Vec<u8>),
Failure(Failure),
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Failure {
pub code: u16,
pub message: String,
}
#[derive(Debug)]
pub enum RunEnterResult {
Executed(NonEmptyValue),
NotExecuted,
}
#[derive(Debug, Clone)]
pub enum NonEmptyValue {
Success(Vec<u8>),
Failure(Failure),
}
impl From<NonEmptyValue> for Value {
fn from(value: NonEmptyValue) -> Self {
match value {
NonEmptyValue::Success(s) => Value::Success(s),
NonEmptyValue::Failure(f) => Value::Failure(f),
}
}
}
#[derive(Debug, Eq, PartialEq)]
pub enum TakeOutputResult {
Buffer(Vec<u8>),
EOF,
}
pub type VMResult<T> = Result<T, VMError>;
pub trait VM: Sized {
fn new(request_headers: Vec<(String, String)>) -> VMResult<Self>;
fn get_response_head(&self) -> ResponseHead;
fn notify_input(&mut self, buffer: Vec<u8>);
fn notify_input_closed(&mut self);
fn notify_error(&mut self, message: Cow<'static, str>, description: Cow<'static, str>);
fn take_output(&mut self) -> TakeOutputResult;
fn is_ready_to_execute(&self) -> Result<bool, VMError>;
fn notify_await_point(&mut self, handle: AsyncResultHandle);
fn take_async_result(
&mut self,
handle: AsyncResultHandle,
) -> Result<Option<Value>, SuspendedOrVMError>;
fn sys_input(&mut self) -> VMResult<Input>;
fn sys_get_state(&mut self, key: String) -> VMResult<AsyncResultHandle>;
fn sys_set_state(&mut self, key: String, value: Vec<u8>) -> VMResult<()>;
fn sys_clear_state(&mut self, key: String) -> VMResult<()>;
fn sys_clear_all_state(&mut self) -> VMResult<()>;
fn sys_sleep(&mut self, duration: Duration) -> VMResult<AsyncResultHandle>;
fn sys_call(&mut self, target: Target, input: Vec<u8>) -> VMResult<AsyncResultHandle>;
fn sys_send(&mut self, target: Target, input: Vec<u8>, delay: Option<Duration>)
-> VMResult<()>;
fn sys_awakeable(&mut self) -> VMResult<(String, AsyncResultHandle)>;
fn sys_complete_awakeable(&mut self, id: String, value: NonEmptyValue) -> VMResult<()>;
fn sys_get_promise(&mut self, key: String) -> VMResult<AsyncResultHandle>;
fn sys_peek_promise(&mut self, key: String) -> VMResult<AsyncResultHandle>;
fn sys_complete_promise(
&mut self,
key: String,
value: NonEmptyValue,
) -> VMResult<AsyncResultHandle>;
fn sys_run_enter(&mut self, name: String) -> VMResult<RunEnterResult>;
fn sys_run_exit(&mut self, value: NonEmptyValue) -> VMResult<AsyncResultHandle>;
fn sys_write_output(&mut self, value: NonEmptyValue) -> VMResult<()>;
fn sys_end(&mut self) -> VMResult<()>;
}
#[cfg(test)]
mod tests;