Skip to main content

harmos_sdk/operations/
calls.rs

1/* ***
2 *
3 * Harmos
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * ***
8 */
9
10/* === Modules === */
11
12/* === Re-Exports === */
13
14/* === Imports === */
15
16// Standard Library Imports
17use std::any::{Any, TypeId};
18use std::future::Future;
19use std::pin::Pin;
20use std::sync::Arc;
21
22// Third Party Imports
23
24// Local Imports
25use super::response::ErasedResponse;
26use super::{CacheKey, OperationDeclaration, OperationDefinition, Response};
27use crate::{Message, MessageError};
28
29/* === Constants === */
30
31/* === Macros === */
32
33/* === Type Aliases === */
34
35pub type CallFuture<'a> = Pin<Box<dyn Future<Output = Result<ErasedResponse, InvocationError>> + Send + 'a>>;
36
37/* === Structs === */
38
39// The Carrier Caller Of One Attempt, Inserted Into Its Execution Snapshot.
40#[derive(Clone)]
41pub struct Calls(pub Arc<dyn Caller>);
42
43// A Child Operation Erased For Carrier Dispatch; Every Function Is Monomorphized For The Callee.
44#[derive(Clone, Copy)]
45pub struct Target {
46    pub id: &'static str,
47    pub definition: fn() -> OperationDefinition,
48    pub request: fn() -> TypeId,
49    pub memory: fn(&(dyn Any + Send)) -> usize,
50    pub response: fn() -> TypeId,
51    pub encode: fn(&(dyn Any + Send)) -> Option<Vec<u8>>,
52    pub decode: fn(&[u8]) -> Result<ErasedResponse, MessageError>,
53    pub grant: fn(&(dyn Any + Send)) -> Option<crate::plugin::Grant>,
54    pub key: fn(&(dyn Any + Send)) -> Option<CacheKey>,
55}
56
57/* === Enums === */
58
59#[derive(Debug, thiserror::Error)]
60pub enum InvocationError {
61    #[error("operation `{operation}` cannot be invoked from this carrier")]
62    Unavailable { operation: &'static str },
63
64    #[error("operation `{operation}` answered a response of another type")]
65    Response { operation: &'static str },
66
67    #[error("operation `{operation}` failed: {source}")]
68    Failed { operation: &'static str, source: Arc<dyn std::error::Error + Send + Sync> },
69}
70
71/* === Traits === */
72
73// Carriers Route A Declared Child Operation With The Calling Attempt's Metadata.
74pub trait Caller: Send + Sync + 'static {
75    fn call(&self, target: Target, request: Box<dyn Any + Send>) -> CallFuture<'_>;
76}
77
78/* === Implementations === */
79
80impl Target {
81    pub fn of<T: OperationDeclaration>() -> Self {
82        Self {
83            id: T::ID,
84            definition: T::definition,
85            request: TypeId::of::<T::Request>,
86            memory: |request| request.downcast_ref::<T::Request>().map_or(0, crate::MemorySize::memory_size),
87            response: TypeId::of::<T::Response>,
88            encode: |request| request.downcast_ref::<T::Request>().map(Message::encode),
89            decode: decode::<T>,
90            grant: |request| request.downcast_ref::<T::Request>().and_then(T::grant),
91            key: |request| request.downcast_ref::<T::Request>().and_then(T::key),
92        }
93    }
94}
95
96impl InvocationError {
97    pub fn failed(operation: &'static str, source: impl std::error::Error + Send + Sync + 'static) -> Self {
98        Self::Failed { operation, source: Arc::new(source) }
99    }
100}
101
102/* === Public Functions === */
103
104/* === Private Functions === */
105
106fn decode<T: OperationDeclaration>(bytes: &[u8]) -> Result<ErasedResponse, MessageError> {
107    let response = T::Response::decode(bytes)?;
108    Ok(Response::new(response).into_erased())
109}
110
111/* === Tests === */