Skip to main content

harmos_domain/operations/
mod.rs

1/* ***
2 *
3 * Harmos
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * ***
8 */
9
10/* === Modules === */
11
12mod catalog;
13mod context;
14mod contract;
15mod direction;
16mod grpc;
17pub mod instance;
18mod key;
19#[doc(hidden)]
20pub mod payload;
21
22/* === Re-Exports === */
23
24pub use crate::model::operations::policy::{Backoff, FailureKind, Jitter, OperationPolicy, PolicyError, ReplaySafety, RetryPolicy};
25pub use crate::model::services::policy::{RestartPolicy, ServicePolicy};
26pub use crate::observers;
27pub use catalog::{Callees, Declarations, Entry};
28pub use context::{CallContext, CallValue, ContextError, ContextValue, PORTABLE_BYTES, PORTABLE_VALUES};
29pub use contract::{Codec, Contract, ContractError, Contracts, WireDeclaration};
30pub use direction::{Direction, NoStream, Stream, item_types};
31pub use grpc::Grpc;
32pub use key::{CacheKey, CacheKeyError, MAX_CACHE_KEY_BYTES};
33
34/* === Imports === */
35
36// Standard Library Imports
37
38// Third Party Imports
39use serde::{Deserialize, Serialize};
40// Local Imports
41use crate::Identifier;
42
43/* === Constants === */
44
45// A deadline no caller reaches: resident and watch policies run until stopped.
46pub const UNBOUNDED: std::time::Duration = std::time::Duration::from_secs(1 << 32);
47
48/* === Macros === */
49
50/* === Type Aliases === */
51
52/* === Structs === */
53
54#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
55pub struct OperationDefinition {
56    pub id: Identifier,
57    pub description: String,
58    pub policy: OperationPolicy,
59    pub visibility: Visibility,
60    pub replay: ReplaySafety,
61    pub fingerprint: crate::Fingerprint,
62}
63
64// The decoder constructs the canonical type directly, then checks admission.
65// No second public metadata contract or JSON-value staging exists.
66#[derive(Deserialize)]
67#[serde(remote = "OperationDefinition", deny_unknown_fields)]
68struct DecodedOperationDefinition {
69    id: Identifier,
70    description: String,
71    policy: OperationPolicy,
72    visibility: Visibility,
73    replay: ReplaySafety,
74    fingerprint: crate::Fingerprint,
75}
76
77/* === Enums === */
78
79#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
80#[serde(rename_all = "snake_case")]
81pub enum Visibility {
82    Private,
83    Shared,
84    Host,
85}
86
87/* === Traits === */
88
89pub trait OperationDeclaration: 'static {
90    type Request: crate::Portable;
91    type Response: crate::Portable;
92    type Input: Direction;
93    type Output: Direction;
94
95    const ID: &'static str;
96    const POLICY: OperationPolicy;
97    const DESCRIPTION: &'static str = "";
98    const VISIBILITY: Visibility = Visibility::Private;
99    const REPLAY: ReplaySafety = ReplaySafety::Unknown;
100    const GRPC: Option<Grpc> = None;
101
102    // The operations this one invokes; catalogs aggregate them into plugin requirements.
103    const OPERATIONS: &'static [WireDeclaration] = &[];
104
105    fn definition() -> OperationDefinition {
106        Entry::of::<Self>().declared().expect("representable operation declaration")
107    }
108
109    fn grant(_request: &Self::Request) -> Option<crate::plugin::Grant> {
110        None
111    }
112
113    fn key(_request: &Self::Request) -> Option<CacheKey> {
114        None
115    }
116}
117
118// The Execution Resource Types An Operation Declares With `resources = [..]`.
119pub trait Requires<T: ?Sized> {}
120
121// The Operations An Operation Declares With `operations = [..]`.
122pub trait Invokes<T: OperationDeclaration> {}
123
124/* === Implementations === */
125
126impl<'de> Deserialize<'de> for OperationDefinition {
127    fn deserialize<D: serde::Deserializer<'de>>(decoder: D) -> Result<Self, D::Error> {
128        let definition = DecodedOperationDefinition::deserialize(decoder)?;
129        definition.validate().map_err(serde::de::Error::custom)?;
130        Ok(definition)
131    }
132}
133
134impl OperationDefinition {
135    pub fn validate(&self) -> crate::Result<()> {
136        if crate::reserved(self.id.as_str()) {
137            return Err(crate::Error::ReservedOperation { id: self.id.as_str().to_owned() });
138        }
139        if !crate::identity::dotted(self.id.as_str()) {
140            return Err(crate::Error::InvalidOperation { id: self.id.to_string() });
141        }
142        self.policy.validate()?;
143        Ok(())
144    }
145
146    pub fn of<O: OperationDeclaration + ?Sized>() -> crate::Result<Self> {
147        Entry::of::<O>().definition()
148    }
149}
150
151/* === Public Functions === */
152
153/* === Private Functions === */
154
155/* === Tests === */