use crate::endpoint::{ContextInternal, InputMetadata};
use crate::errors::{HandlerResult, TerminalError};
use crate::serde::{Deserialize, Serialize};
use std::future::Future;
use std::time::Duration;
#[doc(hidden)]
pub mod macro_support;
mod request;
mod run;
mod select;
mod select_any;
pub use request::{CallFuture, InvocationHandle, Request, RequestTarget};
pub use run::{RunClosure, RunFuture, RunRetryPolicy};
pub use select_any::DurableFuturesUnordered;
pub type HeaderMap = http::HeaderMap<String>;
pub struct Context<'ctx> {
invocation_id: String,
random_seed: u64,
#[cfg(feature = "rand")]
std_rng: rand::prelude::StdRng,
headers: HeaderMap,
inner: &'ctx ContextInternal,
}
impl Context<'_> {
pub fn invocation_id(&self) -> &str {
&self.invocation_id
}
pub fn headers(&self) -> &HeaderMap {
&self.headers
}
pub fn headers_mut(&mut self) -> &HeaderMap {
&mut self.headers
}
}
impl<'ctx> From<(&'ctx ContextInternal, InputMetadata)> for Context<'ctx> {
fn from(value: (&'ctx ContextInternal, InputMetadata)) -> Self {
Self {
invocation_id: value.1.invocation_id,
random_seed: value.1.random_seed,
#[cfg(feature = "rand")]
std_rng: rand::prelude::SeedableRng::seed_from_u64(value.1.random_seed),
headers: value.1.headers,
inner: value.0,
}
}
}
pub struct SharedObjectContext<'ctx> {
invocation_id: String,
key: String,
random_seed: u64,
#[cfg(feature = "rand")]
std_rng: rand::prelude::StdRng,
headers: HeaderMap,
pub(crate) inner: &'ctx ContextInternal,
}
impl SharedObjectContext<'_> {
pub fn invocation_id(&self) -> &str {
&self.invocation_id
}
pub fn key(&self) -> &str {
&self.key
}
pub fn headers(&self) -> &HeaderMap {
&self.headers
}
pub fn headers_mut(&mut self) -> &HeaderMap {
&mut self.headers
}
}
impl<'ctx> From<(&'ctx ContextInternal, InputMetadata)> for SharedObjectContext<'ctx> {
fn from(value: (&'ctx ContextInternal, InputMetadata)) -> Self {
Self {
invocation_id: value.1.invocation_id,
key: value.1.key,
random_seed: value.1.random_seed,
#[cfg(feature = "rand")]
std_rng: rand::prelude::SeedableRng::seed_from_u64(value.1.random_seed),
headers: value.1.headers,
inner: value.0,
}
}
}
pub struct ObjectContext<'ctx> {
invocation_id: String,
key: String,
random_seed: u64,
#[cfg(feature = "rand")]
std_rng: rand::prelude::StdRng,
headers: HeaderMap,
pub(crate) inner: &'ctx ContextInternal,
}
impl ObjectContext<'_> {
pub fn invocation_id(&self) -> &str {
&self.invocation_id
}
pub fn key(&self) -> &str {
&self.key
}
pub fn headers(&self) -> &HeaderMap {
&self.headers
}
pub fn headers_mut(&mut self) -> &HeaderMap {
&mut self.headers
}
}
impl<'ctx> From<(&'ctx ContextInternal, InputMetadata)> for ObjectContext<'ctx> {
fn from(value: (&'ctx ContextInternal, InputMetadata)) -> Self {
Self {
invocation_id: value.1.invocation_id,
key: value.1.key,
random_seed: value.1.random_seed,
#[cfg(feature = "rand")]
std_rng: rand::prelude::SeedableRng::seed_from_u64(value.1.random_seed),
headers: value.1.headers,
inner: value.0,
}
}
}
pub struct SharedWorkflowContext<'ctx> {
invocation_id: String,
key: String,
random_seed: u64,
#[cfg(feature = "rand")]
std_rng: rand::prelude::StdRng,
headers: HeaderMap,
pub(crate) inner: &'ctx ContextInternal,
}
impl<'ctx> From<(&'ctx ContextInternal, InputMetadata)> for SharedWorkflowContext<'ctx> {
fn from(value: (&'ctx ContextInternal, InputMetadata)) -> Self {
Self {
invocation_id: value.1.invocation_id,
key: value.1.key,
random_seed: value.1.random_seed,
#[cfg(feature = "rand")]
std_rng: rand::prelude::SeedableRng::seed_from_u64(value.1.random_seed),
headers: value.1.headers,
inner: value.0,
}
}
}
impl SharedWorkflowContext<'_> {
pub fn invocation_id(&self) -> &str {
&self.invocation_id
}
pub fn key(&self) -> &str {
&self.key
}
pub fn headers(&self) -> &HeaderMap {
&self.headers
}
pub fn headers_mut(&mut self) -> &HeaderMap {
&mut self.headers
}
}
pub struct WorkflowContext<'ctx> {
invocation_id: String,
key: String,
random_seed: u64,
#[cfg(feature = "rand")]
std_rng: rand::prelude::StdRng,
headers: HeaderMap,
pub(crate) inner: &'ctx ContextInternal,
}
impl<'ctx> From<(&'ctx ContextInternal, InputMetadata)> for WorkflowContext<'ctx> {
fn from(value: (&'ctx ContextInternal, InputMetadata)) -> Self {
Self {
invocation_id: value.1.invocation_id,
key: value.1.key,
random_seed: value.1.random_seed,
#[cfg(feature = "rand")]
std_rng: rand::prelude::SeedableRng::seed_from_u64(value.1.random_seed),
headers: value.1.headers,
inner: value.0,
}
}
}
impl WorkflowContext<'_> {
pub fn invocation_id(&self) -> &str {
&self.invocation_id
}
pub fn key(&self) -> &str {
&self.key
}
pub fn headers(&self) -> &HeaderMap {
&self.headers
}
pub fn headers_mut(&mut self) -> &HeaderMap {
&mut self.headers
}
}
pub trait ContextTimers<'ctx>: private::SealedContext<'ctx> {
fn sleep(
&self,
duration: Duration,
) -> impl DurableFuture<Output = Result<(), TerminalError>> + 'ctx {
private::SealedContext::inner_context(self).sleep(duration)
}
}
impl<'ctx, CTX: private::SealedContext<'ctx>> ContextTimers<'ctx> for CTX {}
pub trait ContextClient<'ctx>: private::SealedContext<'ctx> {
fn request<Req, Res>(
&self,
request_target: RequestTarget,
req: Req,
) -> Request<'ctx, Req, Res> {
Request::new(self.inner_context(), request_target, req)
}
fn invocation_handle(&self, invocation_id: String) -> impl InvocationHandle + 'ctx {
self.inner_context().invocation_handle(invocation_id)
}
fn service_client<C>(&self) -> C
where
C: IntoServiceClient<'ctx>,
{
C::create_client(self.inner_context())
}
fn object_client<C>(&self, key: impl Into<String>) -> C
where
C: IntoObjectClient<'ctx>,
{
C::create_client(self.inner_context(), key.into())
}
fn workflow_client<C>(&self, key: impl Into<String>) -> C
where
C: IntoWorkflowClient<'ctx>,
{
C::create_client(self.inner_context(), key.into())
}
}
pub trait IntoServiceClient<'ctx>: Sized {
fn create_client(ctx: &'ctx ContextInternal) -> Self;
}
pub trait IntoObjectClient<'ctx>: Sized {
fn create_client(ctx: &'ctx ContextInternal, key: String) -> Self;
}
pub trait IntoWorkflowClient<'ctx>: Sized {
fn create_client(ctx: &'ctx ContextInternal, key: String) -> Self;
}
impl<'ctx, CTX: private::SealedContext<'ctx>> ContextClient<'ctx> for CTX {}
pub trait ContextAwakeables<'ctx>: private::SealedContext<'ctx> {
fn awakeable<T: Deserialize + 'static>(
&self,
) -> (
String,
impl DurableFuture<Output = Result<T, TerminalError>> + Send + 'ctx,
) {
self.inner_context().awakeable()
}
fn resolve_awakeable<T: Serialize + 'static>(&self, key: &str, t: T) {
self.inner_context().resolve_awakeable(key, t)
}
fn reject_awakeable(&self, key: &str, failure: TerminalError) {
self.inner_context().reject_awakeable(key, failure)
}
}
impl<'ctx, CTX: private::SealedContext<'ctx>> ContextAwakeables<'ctx> for CTX {}
pub trait ContextSideEffects<'ctx>: private::SealedContext<'ctx> {
#[must_use]
fn run<R, F, T>(&self, run_closure: R) -> impl RunFuture<Result<T, TerminalError>> + 'ctx
where
R: RunClosure<Fut = F, Output = T> + Send + 'ctx,
F: Future<Output = HandlerResult<T>> + Send + 'ctx,
T: Serialize + Deserialize + 'static,
{
self.inner_context().run(run_closure)
}
fn random_seed(&self) -> u64 {
private::SealedContext::random_seed(self)
}
#[cfg(feature = "rand")]
fn rand(&mut self) -> &mut rand::prelude::StdRng {
private::SealedContext::rand(self)
}
#[cfg(all(feature = "rand", feature = "uuid"))]
fn rand_uuid(&mut self) -> uuid::Uuid {
let rand = private::SealedContext::rand(self);
uuid::Uuid::from_u64_pair(rand::Rng::next_u64(rand), rand::Rng::next_u64(rand))
}
}
impl<'ctx, CTX: private::SealedContext<'ctx>> ContextSideEffects<'ctx> for CTX {}
pub trait ContextReadState<'ctx>: private::SealedContext<'ctx> {
fn get<T: Deserialize + 'static>(
&self,
key: &'ctx str,
) -> impl Future<Output = Result<Option<T>, TerminalError>> + 'ctx {
self.inner_context().get(key)
}
fn get_keys(&'ctx self) -> impl Future<Output = Result<Vec<String>, TerminalError>> + 'ctx {
self.inner_context().get_keys()
}
}
impl<'ctx, CTX: private::SealedContext<'ctx> + private::SealedCanReadState> ContextReadState<'ctx>
for CTX
{
}
pub trait ContextWriteState<'ctx>: private::SealedContext<'ctx> {
fn set<T: Serialize + 'static>(&self, key: &str, t: T) {
self.inner_context().set(key, t)
}
fn clear(&self, key: &str) {
self.inner_context().clear(key)
}
fn clear_all(&self) {
self.inner_context().clear_all()
}
}
impl<'ctx, CTX: private::SealedContext<'ctx> + private::SealedCanWriteState> ContextWriteState<'ctx>
for CTX
{
}
pub trait ContextPromises<'ctx>: private::SealedContext<'ctx> {
fn promise<T: Deserialize + 'static>(
&'ctx self,
key: &'ctx str,
) -> impl DurableFuture<Output = Result<T, TerminalError>> + 'ctx {
self.inner_context().promise(key)
}
fn peek_promise<T: Deserialize + 'static>(
&self,
key: &'ctx str,
) -> impl Future<Output = Result<Option<T>, TerminalError>> + 'ctx {
self.inner_context().peek_promise(key)
}
fn resolve_promise<T: Serialize + 'static>(&self, key: &str, t: T) {
self.inner_context().resolve_promise(key, t)
}
fn reject_promise(&self, key: &str, failure: TerminalError) {
self.inner_context().reject_promise(key, failure)
}
}
impl<'ctx, CTX: private::SealedContext<'ctx> + private::SealedCanUsePromises> ContextPromises<'ctx>
for CTX
{
}
pub trait DurableFuture: Future + macro_support::SealedDurableFuture {}
pub(crate) mod private {
use super::*;
pub trait SealedContext<'ctx> {
fn inner_context(&self) -> &'ctx ContextInternal;
fn random_seed(&self) -> u64;
#[cfg(feature = "rand")]
fn rand(&mut self) -> &mut rand::prelude::StdRng;
}
pub trait SealedCanReadState {}
pub trait SealedCanWriteState {}
pub trait SealedCanUsePromises {}
impl<'ctx> SealedContext<'ctx> for Context<'ctx> {
fn inner_context(&self) -> &'ctx ContextInternal {
self.inner
}
fn random_seed(&self) -> u64 {
self.random_seed
}
#[cfg(feature = "rand")]
fn rand(&mut self) -> &mut rand::prelude::StdRng {
&mut self.std_rng
}
}
impl<'ctx> SealedContext<'ctx> for SharedObjectContext<'ctx> {
fn inner_context(&self) -> &'ctx ContextInternal {
self.inner
}
fn random_seed(&self) -> u64 {
self.random_seed
}
#[cfg(feature = "rand")]
fn rand(&mut self) -> &mut rand::prelude::StdRng {
&mut self.std_rng
}
}
impl SealedCanReadState for SharedObjectContext<'_> {}
impl<'ctx> SealedContext<'ctx> for ObjectContext<'ctx> {
fn inner_context(&self) -> &'ctx ContextInternal {
self.inner
}
fn random_seed(&self) -> u64 {
self.random_seed
}
#[cfg(feature = "rand")]
fn rand(&mut self) -> &mut rand::prelude::StdRng {
&mut self.std_rng
}
}
impl SealedCanReadState for ObjectContext<'_> {}
impl SealedCanWriteState for ObjectContext<'_> {}
impl<'ctx> SealedContext<'ctx> for SharedWorkflowContext<'ctx> {
fn inner_context(&self) -> &'ctx ContextInternal {
self.inner
}
fn random_seed(&self) -> u64 {
self.random_seed
}
#[cfg(feature = "rand")]
fn rand(&mut self) -> &mut rand::prelude::StdRng {
&mut self.std_rng
}
}
impl SealedCanReadState for SharedWorkflowContext<'_> {}
impl SealedCanUsePromises for SharedWorkflowContext<'_> {}
impl<'ctx> SealedContext<'ctx> for WorkflowContext<'ctx> {
fn inner_context(&self) -> &'ctx ContextInternal {
self.inner
}
fn random_seed(&self) -> u64 {
self.random_seed
}
#[cfg(feature = "rand")]
fn rand(&mut self) -> &mut rand::prelude::StdRng {
&mut self.std_rng
}
}
impl SealedCanReadState for WorkflowContext<'_> {}
impl SealedCanWriteState for WorkflowContext<'_> {}
impl SealedCanUsePromises for WorkflowContext<'_> {}
}