harmos_domain/operations/
catalog.rs1use std::collections::BTreeSet;
18use super::{Direction, OperationDeclaration, OperationDefinition, OperationPolicy, ReplaySafety, Visibility};
22use crate::catalog::{self, Catalog, Member, Node, Projection, Visitor};
23use crate::{Error, Identifier, Result};
24
25#[derive(Clone, Copy, Debug)]
34pub struct Entry {
35 pub id: &'static str,
36 pub description: &'static str,
37 pub policy: OperationPolicy,
38 pub visibility: Visibility,
39 pub replay: ReplaySafety,
40 pub fingerprint: fn() -> Result<crate::Fingerprint>,
41}
42
43pub struct Declarations;
44
45pub struct Callees;
46
47impl PartialEq for Entry {
54 fn eq(&self, other: &Self) -> bool {
55 self.id == other.id
56 && self.description == other.description
57 && self.policy == other.policy
58 && self.visibility == other.visibility
59 && self.replay == other.replay
60 && (self.fingerprint)().ok() == (other.fingerprint)().ok()
61 }
62}
63
64impl Eq for Entry {}
65
66impl Entry {
67 pub const fn of<O: OperationDeclaration + ?Sized>() -> Self {
68 Self {
69 id: O::ID,
70 description: O::DESCRIPTION,
71 policy: O::POLICY,
72 visibility: O::VISIBILITY,
73 replay: O::REPLAY,
74 fingerprint: fingerprint::<O>,
75 }
76 }
77
78 pub fn definition(&self) -> Result<OperationDefinition> {
79 let definition = self.declared()?;
80 definition.validate()?;
81 Ok(definition)
82 }
83
84 pub(super) fn declared(&self) -> Result<OperationDefinition> {
85 let id = Identifier::new(self.id)?;
86 let definition = OperationDefinition {
87 id,
88 description: self.description.to_owned(),
89 policy: self.policy,
90 visibility: self.visibility,
91 replay: self.replay,
92 fingerprint: (self.fingerprint)()?,
93 };
94 Ok(definition)
95 }
96}
97
98impl Visitor for Declarations {
99 type Entry = Entry;
100}
101
102impl<M: OperationDeclaration> Member<M> for Declarations {
103 const ENTRY: Entry = Entry::of::<M>();
104}
105
106impl Declarations {
107 pub fn of<C: Catalog<Self>>() -> Result<Vec<OperationDefinition>> {
108 Self::from_projection(&C::ENTRIES)
109 }
110
111 pub fn from_entries(entries: &[Entry]) -> Result<Vec<OperationDefinition>> {
112 let mut names = BTreeSet::new();
113 let mut definitions = Vec::with_capacity(entries.len());
114 for declaration in entries {
115 append(declaration, &mut names, &mut definitions)?;
116 }
117 Ok(definitions)
118 }
119
120 pub fn from_tree(entries: &[Node<Entry>]) -> Result<Vec<OperationDefinition>> {
121 let mut names = BTreeSet::new();
122 let mut definitions = Vec::with_capacity(catalog::count(entries));
123 catalog::try_for_each(entries, |declaration| append(declaration, &mut names, &mut definitions))?;
124 Ok(definitions)
125 }
126
127 pub fn from_projection<P: Projection<Entry>>(entries: &P) -> Result<Vec<OperationDefinition>> {
128 let mut names = BTreeSet::new();
129 let mut definitions = Vec::with_capacity(P::LEN);
130 entries.try_for_each(|declaration| append(declaration, &mut names, &mut definitions))?;
131 Ok(definitions)
132 }
133}
134
135impl Visitor for Callees {
136 type Entry = &'static [super::WireDeclaration];
137}
138
139impl<M: OperationDeclaration> Member<M> for Callees {
140 const ENTRY: Self::Entry = M::OPERATIONS;
141}
142
143fn payload<T: crate::Portable>() -> Result<crate::Fingerprint> {
148 let schema = crate::schema::graph::Schema::from_declaration(T::DEFINITION, &crate::config::SchemaSettings::default())
149 .map_err(|error| crate::MessageError::new(error.to_string()))?;
150 let root = schema.root().map_err(|error| crate::MessageError::new(error.to_string()))?;
151 crate::schema::identity::fingerprint(root, T::CODEC).map_err(|error| crate::MessageError::new(error.to_string()).into())
152}
153
154fn fingerprint<O: OperationDeclaration + ?Sized>() -> Result<crate::Fingerprint> {
155 let input = if O::Input::STREAMED { Some(payload::<<O::Input as super::Direction>::Item>()?) } else { None };
156 let output = if O::Output::STREAMED { Some(payload::<<O::Output as super::Direction>::Item>()?) } else { None };
157 Ok(crate::schema::identity::operation(O::ID, payload::<O::Request>()?, payload::<O::Response>()?, input, output))
158}
159
160fn append(declaration: &Entry, names: &mut BTreeSet<Identifier>, definitions: &mut Vec<OperationDefinition>) -> Result<()> {
161 let definition = declaration.definition()?;
162 if !names.insert(definition.id.clone()) {
163 return Err(Error::DuplicateOperation { id: declaration.id.to_owned() });
164 }
165 definitions.push(definition);
166 Ok(())
167}
168
169