harmos_domain/plugin/
requirement.rs1use std::borrow::Cow;
18use serde::{Deserialize, Serialize};
20use crate::catalog::{Member, Visitor};
22use crate::operations::{OperationDeclaration, WireDeclaration};
23
24#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
36#[serde(rename_all = "snake_case", deny_unknown_fields)]
37pub struct Grant {
38 pub operation: Cow<'static, str>,
39
40 #[serde(default, skip_serializing_if = "Option::is_none")]
41 pub scope: Option<Cow<'static, str>>,
42}
43
44pub struct Requirement {
45 pub declaration: WireDeclaration,
46 pub grants: &'static [Grant],
47}
48
49pub struct Requirements;
50
51impl Requirement {
58 pub const fn of<O: OperationDeclaration>(grants: &'static [Grant]) -> Self {
59 Self {
60 declaration: WireDeclaration::of::<O>(),
61 grants,
62 }
63 }
64}
65
66impl Grant {
67 pub fn of(operation: impl Into<Cow<'static, str>>, scope: impl Into<Cow<'static, str>>) -> Self {
68 Self {
69 operation: operation.into(),
70 scope: Some(scope.into()),
71 }
72 }
73
74 pub fn operation(&self) -> &str {
75 &self.operation
76 }
77
78 pub fn scope(&self) -> Option<&str> {
79 self.scope.as_deref()
80 }
81
82 pub(crate) const fn borrowed(&self) -> (&'static str, Option<&'static str>) {
83 let operation = match &self.operation {
84 Cow::Borrowed(value) => *value,
85 Cow::Owned(_) => panic!("const grants must be borrowed"),
86 };
87 let scope = match &self.scope {
88 None => None,
89 Some(Cow::Borrowed(value)) => Some(*value),
90 Some(Cow::Owned(_)) => panic!("const grants must be borrowed"),
91 };
92 (operation, scope)
93 }
94}
95
96impl Visitor for Requirements {
97 type Entry = Requirement;
98}
99
100impl<M> Member<M> for Requirements
101where
102 M: OperationDeclaration,
103{
104 const ENTRY: Requirement = Requirement::of::<M>(&[]);
105}
106
107pub const fn callee_count(nodes: &[crate::catalog::Node<&'static [WireDeclaration]>]) -> usize {
111 let mut count = 0;
112 let mut index = 0;
113 while index < nodes.len() {
114 count += match &nodes[index] {
115 crate::catalog::Node::Leaf(entries) => entries.len(),
116 crate::catalog::Node::Nested(entries) => callee_count(entries),
117 };
118 index += 1;
119 }
120 count
121}
122
123pub const fn aggregate<const N: usize>(
124 explicit: &'static [crate::catalog::Node<Requirement>], provided: &[crate::catalog::Node<WireDeclaration>],
125 callees: &[crate::catalog::Node<&'static [WireDeclaration]>],
126) -> [crate::catalog::Node<Requirement>; N] {
127 let mut output = [const { crate::catalog::Node::Nested(&[]) }; N];
128 std::mem::forget(std::mem::replace(&mut output[0], crate::catalog::Node::Nested(explicit)));
129 let mut cursor = 1;
130 append_callees(callees, provided, &mut output, &mut cursor);
131 output
132}
133
134const fn same(left: &str, right: &str) -> bool {
137 let left = left.as_bytes();
138 let right = right.as_bytes();
139 if left.len() != right.len() {
140 return false;
141 }
142 let mut index = 0;
143 while index < left.len() {
144 if left[index] != right[index] {
145 return false;
146 }
147 index += 1;
148 }
149 true
150}
151
152const fn provided(nodes: &[crate::catalog::Node<WireDeclaration>], id: &str) -> bool {
153 let mut index = 0;
154 while index < nodes.len() {
155 let found = match &nodes[index] {
156 crate::catalog::Node::Leaf(entry) => same(entry.operation.id, id),
157 crate::catalog::Node::Nested(entries) => provided(entries, id),
158 };
159 if found {
160 return true;
161 }
162 index += 1;
163 }
164 false
165}
166
167const fn required(nodes: &[crate::catalog::Node<Requirement>], id: &str) -> bool {
168 let mut index = 0;
169 while index < nodes.len() {
170 let found = match &nodes[index] {
171 crate::catalog::Node::Leaf(entry) => same(entry.declaration.operation.id, id),
172 crate::catalog::Node::Nested(entries) => required(entries, id),
173 };
174 if found {
175 return true;
176 }
177 index += 1;
178 }
179 false
180}
181
182const fn append_callees(
183 nodes: &[crate::catalog::Node<&'static [WireDeclaration]>], providers: &[crate::catalog::Node<WireDeclaration>],
184 output: &mut [crate::catalog::Node<Requirement>], cursor: &mut usize,
185) {
186 let mut index = 0;
187 while index < nodes.len() {
188 match &nodes[index] {
189 crate::catalog::Node::Nested(entries) => append_callees(entries, providers, output, cursor),
190 crate::catalog::Node::Leaf(entries) => {
191 let mut member = 0;
192 while member < entries.len() {
193 let declaration = &entries[member];
194 let id = declaration.operation.id;
195 if !provided(providers, id) && !required(output, id) {
196 std::mem::forget(std::mem::replace(
197 &mut output[*cursor],
198 crate::catalog::Node::Leaf(Requirement {
199 declaration: declaration.copied(),
200 grants: &[],
201 }),
202 ));
203 *cursor += 1;
204 }
205 member += 1;
206 }
207 }
208 }
209 index += 1;
210 }
211}
212
213