mod catalog;
mod context;
mod contract;
mod direction;
mod grpc;
pub mod instance;
mod key;
pub(crate) mod payload;
mod policy;
pub use crate::observers;
pub use catalog::{Declarations, Entry};
pub use context::{CallContext, CallValue, ContextError, ContextValue, PORTABLE_BYTES, PORTABLE_VALUES};
pub use contract::{Codec, Contract, ContractError, Contracts, WireDeclaration};
pub use direction::{Direction, NoStream, Stream, item_types};
pub use grpc::Grpc;
pub use key::{CacheKey, CacheKeyError, MAX_CACHE_KEY_BYTES};
pub use policy::{Backoff, FailureKind, Jitter, OperationPolicy, PolicyError, ReplaySafety, RestartPolicy, RetryPolicy};
use serde::{Deserialize, Serialize};
use crate::Identifier;
pub const UNBOUNDED: std::time::Duration = std::time::Duration::from_secs(1 << 32);
#[macro_export]
macro_rules! declare {
($ty:ty {
id: $id:expr,
version: $version:expr,
policy: $policy:expr,
response: $response:ty
$(, input: $input:ty)?
$(, output: $output:ty)?
$(, description: $description:expr)?
$(, visibility: $visibility:expr)?
$(, replay: $replay:expr)?
$(, grpc: ($package:expr, $service:expr, $method:expr))?
$(, grant: $grant:expr)?
$(, key: $key:expr)?
$(,)?
}) => {
impl $crate::operations::OperationDeclaration for $ty {
type Response = $response;
type Input = $crate::declare!(@direction $($input)?);
type Output = $crate::declare!(@direction $($output)?);
const ID: &'static str = $id;
const VERSION: u32 = $version;
const POLICY: $crate::operations::OperationPolicy = $policy;
$(const DESCRIPTION: &'static str = $description;)?
$(const VISIBILITY: $crate::operations::Visibility = $visibility;)?
$(const REPLAY: $crate::operations::ReplaySafety = $replay;)?
$(const GRPC: ::core::option::Option<$crate::operations::Grpc> =
::core::option::Option::Some($crate::operations::Grpc::new($package, $service, $method));)?
$(fn grant(&self) -> ::core::option::Option<$crate::plugin::Grant> {
($grant)(self)
})?
$(fn key(&self) -> ::core::option::Option<$crate::operations::CacheKey> {
($key)(self)
})?
}
};
(@direction) => { $crate::operations::NoStream };
(@direction $item:ty) => { $crate::operations::Stream<$item> };
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
pub struct Definition {
pub id: Identifier,
pub description: String,
pub policy: OperationPolicy,
pub visibility: Visibility,
pub replay: ReplaySafety,
}
#[derive(Deserialize)]
#[serde(remote = "Definition", deny_unknown_fields)]
struct DecodedDefinition {
id: Identifier,
description: String,
policy: OperationPolicy,
visibility: Visibility,
replay: ReplaySafety,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Visibility {
Private,
Shared,
Host,
}
pub trait OperationDeclaration: crate::Portable {
type Response: crate::Portable;
type Input: Direction;
type Output: Direction;
const ID: &'static str;
const VERSION: u32;
const POLICY: OperationPolicy;
const DESCRIPTION: &'static str = "";
const VISIBILITY: Visibility = Visibility::Private;
const REPLAY: ReplaySafety = ReplaySafety::Unknown;
const GRPC: Option<Grpc> = None;
fn grant(&self) -> Option<crate::plugin::Grant> {
None
}
fn key(&self) -> Option<CacheKey> {
None
}
}
pub trait Declares {
type Declaration: OperationDeclaration;
}
impl<O: OperationDeclaration> Declares for O {
type Declaration = O;
}
impl<'de> Deserialize<'de> for Definition {
fn deserialize<D: serde::Deserializer<'de>>(decoder: D) -> Result<Self, D::Error> {
let definition = DecodedDefinition::deserialize(decoder)?;
definition.validate().map_err(serde::de::Error::custom)?;
Ok(definition)
}
}
impl Definition {
pub fn validate(&self) -> crate::Result<()> {
if crate::reserved(self.id.as_str()) {
return Err(crate::Error::ReservedOperation { id: self.id.as_str().to_owned() });
}
self.policy.validate()?;
Ok(())
}
pub fn of<O: OperationDeclaration>() -> crate::Result<Self> {
Entry::of::<O>().definition()
}
}