1use std::hash::{Hash, Hasher};
6use std::path::PathBuf;
7use std::sync::Arc;
8
9use crate::Path;
10
11use crate::error::Error;
12use crate::{CanonicalizeContext, OneOrMany};
13use cm_types::{Availability, BorrowedName, Name};
14use serde::Serialize;
15
16#[derive(Debug, Clone, PartialOrd, Ord, Serialize)]
17#[serde(transparent)]
18pub struct ContextSpanned<T> {
19 pub value: T,
20
21 #[serde(skip)]
22 pub origin: Arc<PathBuf>,
23}
24
25impl<T: PartialEq> PartialEq for ContextSpanned<T> {
26 fn eq(&self, other: &Self) -> bool {
27 self.value == other.value
28 }
29}
30
31impl<T: Eq> Eq for ContextSpanned<T> {}
32
33impl<T: Hash> Hash for ContextSpanned<T> {
34 fn hash<H: Hasher>(&self, state: &mut H) {
35 self.value.hash(state);
36 }
37}
38
39impl<T> ContextSpanned<T> {
40 pub fn map<U, F>(self, f: F) -> ContextSpanned<U>
41 where
42 F: FnOnce(T) -> U,
43 {
44 ContextSpanned { value: f(self.value), origin: self.origin }
45 }
46
47 pub fn new_synthetic(value: T, file: PathBuf) -> Self {
48 Self { value, origin: Arc::new(file) }
49 }
50
51 pub fn maybe_synthetic(val: Option<T>, file: PathBuf) -> Option<Self> {
52 val.map(|v| Self::new_synthetic(v, file))
53 }
54}
55
56impl<T: CanonicalizeContext> CanonicalizeContext for ContextSpanned<T> {
57 fn canonicalize_context(&mut self) {
58 self.value.canonicalize_context();
59 }
60}
61
62impl<T: ContextPathClause> ContextPathClause for ContextSpanned<T> {
63 fn path(&self) -> Option<&ContextSpanned<Path>> {
64 self.value.path()
65 }
66}
67
68pub trait Hydrate {
74 type Output;
75
76 fn hydrate(self, file: &Arc<PathBuf>) -> Result<Self::Output, Error>;
77}
78
79pub fn hydrate_list<P, C>(
80 raw_list: Option<Vec<P>>,
81 file: &Arc<PathBuf>,
82) -> Result<Option<Vec<ContextSpanned<C>>>, Error>
83where
84 P: Hydrate<Output = C>,
85{
86 raw_list
87 .map(|vec| {
88 vec.into_iter()
89 .map(|item| {
90 let context_item_result = item.hydrate(file);
91 context_item_result
92 .map(|c_value| ContextSpanned { value: c_value, origin: file.clone() })
93 })
94 .collect::<Result<Vec<ContextSpanned<C>>, Error>>()
95 })
96 .transpose()
97}
98
99pub fn hydrate_required<P, C>(
100 parsed_value: P,
101 file: &Arc<PathBuf>,
102) -> Result<ContextSpanned<C>, Error>
103where
104 P: Hydrate<Output = C>,
105{
106 let context_value = parsed_value.hydrate(file)?;
107
108 Ok(ContextSpanned { value: context_value, origin: file.clone() })
109}
110
111pub fn hydrate_simple<T>(value: T, file: &Arc<PathBuf>) -> ContextSpanned<T> {
112 ContextSpanned { value, origin: file.clone() }
113}
114
115pub fn hydrate_opt<P, C>(
116 opt: Option<P>,
117 file: &Arc<PathBuf>,
118) -> Result<Option<ContextSpanned<C>>, Error>
119where
120 P: Hydrate<Output = C>,
121{
122 opt.map(|s| hydrate_required(s, file)).transpose()
123}
124
125pub fn hydrate_opt_simple<T>(
126 opt_spanned: Option<T>,
127 file: &Arc<PathBuf>,
128) -> Option<ContextSpanned<T>> {
129 opt_spanned.map(|s| hydrate_simple(s, file))
130}
131
132pub fn option_one_or_many_as_ref_context<T, S: ?Sized>(
133 o: &Option<ContextSpanned<OneOrMany<T>>>,
134) -> Option<ContextSpanned<OneOrMany<&S>>>
135where
136 T: AsRef<S>,
137{
138 o.as_ref().map(|spanned| ContextSpanned {
139 origin: spanned.origin.clone(),
140 value: match &spanned.value {
141 OneOrMany::One(item) => OneOrMany::One(item.as_ref()),
142 OneOrMany::Many(items) => {
143 OneOrMany::Many(items.iter().map(|item| item.as_ref()).collect())
144 }
145 },
146 })
147}
148
149pub trait ContextPathClause {
150 fn path(&self) -> Option<&ContextSpanned<Path>>;
151}
152
153pub trait ContextCapabilityClause: Clone + PartialEq + std::fmt::Debug {
154 fn service(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>>;
155 fn protocol(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>>;
156 fn directory(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>>;
157 fn storage(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>>;
158 fn runner(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>>;
159 fn resolver(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>>;
160 fn dictionary(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>>;
161 fn config(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>>;
162 fn event_stream(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>>;
163 fn origin(&self) -> &Arc<PathBuf>;
164 fn availability(&self) -> Option<ContextSpanned<Availability>>;
165
166 fn set_availability(&mut self, a: Option<ContextSpanned<Availability>>);
167 fn set_service(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>);
168 fn set_protocol(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>);
169 fn set_directory(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>);
170 fn set_storage(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>);
171 fn set_runner(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>);
172 fn set_resolver(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>);
173 fn set_event_stream(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>);
174 fn set_dictionary(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>);
175 fn set_config(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>);
176
177 fn capability_type(&self, origin: Option<Arc<PathBuf>>) -> Result<&'static str, Error> {
182 let mut types = Vec::new();
183 if self.service().is_some() {
184 types.push("service");
185 }
186 if self.protocol().is_some() {
187 types.push("protocol");
188 }
189 if self.directory().is_some() {
190 types.push("directory");
191 }
192 if self.storage().is_some() {
193 types.push("storage");
194 }
195 if self.event_stream().is_some() {
196 types.push("event_stream");
197 }
198 if self.runner().is_some() {
199 types.push("runner");
200 }
201 if self.config().is_some() {
202 types.push("config");
203 }
204 if self.resolver().is_some() {
205 types.push("resolver");
206 }
207 if self.dictionary().is_some() {
208 types.push("dictionary");
209 }
210 match types.len() {
211 0 => {
212 let supported_keywords = self
213 .supported()
214 .into_iter()
215 .map(|k| format!("\"{}\"", k))
216 .collect::<Vec<_>>()
217 .join(", ");
218 Err(Error::validate_context(
219 format!(
220 "`{}` declaration is missing a capability keyword, one of: {}",
221 self.decl_type(),
222 supported_keywords,
223 ),
224 origin,
225 ))
226 }
227 1 => Ok(types[0]),
228 _ => Err(Error::validate_context(
229 format!(
230 "{} declaration has multiple capability types defined: {:?}",
231 self.decl_type(),
232 types
233 ),
234 origin,
235 )),
236 }
237 }
238
239 fn names(&self) -> Vec<ContextSpanned<Name>> {
242 let extract = |field: Option<&ContextSpanned<OneOrMany<&BorrowedName>>>| -> Vec<ContextSpanned<Name>> {
243 match field {
244 Some(wrapper) => match &wrapper.value {
245 OneOrMany::One(n) => vec![ContextSpanned {
248 value: (*n).to_owned(),
249 origin: wrapper.origin.clone(),
250 }],
251 OneOrMany::Many(names) => names
252 .iter()
253 .map(|n| ContextSpanned {
254 value: (*n).to_owned(),
255 origin: wrapper.origin.clone(),
256 })
257 .collect(),
258 },
259 None => vec![],
260 }
261 };
262 let mut res = Vec::new();
264 res.extend(extract(self.service().as_ref()));
265 res.extend(extract(self.protocol().as_ref()));
266 res.extend(extract(self.directory().as_ref()));
267 res.extend(extract(self.storage().as_ref()));
268 res.extend(extract(self.runner().as_ref()));
269 res.extend(extract(self.config().as_ref()));
270 res.extend(extract(self.resolver().as_ref()));
271 res.extend(extract(self.event_stream().as_ref()));
272 res.extend(extract(self.dictionary().as_ref()));
273 res
274 }
275
276 fn set_names(&mut self, names: Vec<ContextSpanned<Name>>) {
278 let cap_type = self.capability_type(None).expect("Cannot set names on empty capability");
279
280 let mut update_field = |wrapped_val: Option<ContextSpanned<OneOrMany<Name>>>| match cap_type
281 {
282 "protocol" => self.set_protocol(wrapped_val),
283 "service" => self.set_service(wrapped_val),
284 "directory" => self.set_directory(wrapped_val),
285 "storage" => self.set_storage(wrapped_val),
286 "runner" => self.set_runner(wrapped_val),
287 "resolver" => self.set_resolver(wrapped_val),
288 "event_stream" => self.set_event_stream(wrapped_val),
289 "dictionary" => self.set_dictionary(wrapped_val),
290 "config" => self.set_config(wrapped_val),
291 _ => panic!("Unknown capability type {}", cap_type),
292 };
293
294 if names.is_empty() {
295 update_field(None);
296 return;
297 }
298
299 let first_origin = names[0].origin.clone();
300
301 let raw_names: Vec<Name> = names.into_iter().map(|n| n.value).collect();
302 let one_or_many = if raw_names.len() == 1 {
303 OneOrMany::One(raw_names.into_iter().next().unwrap())
304 } else {
305 OneOrMany::Many(raw_names)
306 };
307
308 let wrapped = Some(ContextSpanned { value: one_or_many, origin: first_origin });
309
310 update_field(wrapped);
311 }
312
313 fn are_many_names_allowed(&self) -> bool;
315
316 fn decl_type(&self) -> &'static str;
317 fn supported(&self) -> &[&'static str];
318}
319
320impl<T: ContextCapabilityClause> ContextCapabilityClause for ContextSpanned<T> {
321 fn service(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
322 self.value.service()
323 }
324 fn protocol(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
325 self.value.protocol()
326 }
327 fn directory(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
328 self.value.directory()
329 }
330 fn storage(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
331 self.value.storage()
332 }
333 fn runner(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
334 self.value.runner()
335 }
336 fn resolver(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
337 self.value.resolver()
338 }
339 fn dictionary(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
340 self.value.dictionary()
341 }
342 fn config(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
343 self.value.config()
344 }
345 fn event_stream(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>> {
346 self.value.event_stream()
347 }
348
349 fn origin(&self) -> &Arc<PathBuf> {
350 &self.origin
351 }
352
353 fn set_service(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
354 self.value.set_service(o)
355 }
356 fn set_protocol(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
357 self.value.set_protocol(o)
358 }
359 fn set_directory(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
360 self.value.set_directory(o)
361 }
362 fn set_storage(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
363 self.value.set_storage(o)
364 }
365 fn set_runner(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
366 self.value.set_runner(o)
367 }
368 fn set_resolver(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
369 self.value.set_resolver(o)
370 }
371 fn set_event_stream(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
372 self.value.set_event_stream(o)
373 }
374 fn set_dictionary(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
375 self.value.set_dictionary(o)
376 }
377 fn set_config(&mut self, o: Option<ContextSpanned<OneOrMany<Name>>>) {
378 self.value.set_config(o)
379 }
380
381 fn are_many_names_allowed(&self) -> bool {
382 self.value.are_many_names_allowed()
383 }
384 fn decl_type(&self) -> &'static str {
385 self.value.decl_type()
386 }
387 fn supported(&self) -> &[&'static str] {
388 self.value.supported()
389 }
390
391 fn availability(&self) -> Option<ContextSpanned<Availability>> {
392 self.value.availability()
393 }
394 fn set_availability(&mut self, a: Option<ContextSpanned<Availability>>) {
395 self.value.set_availability(a)
396 }
397}
398
399#[macro_export]
400macro_rules! merge_spanned_vec {
401 ($self:expr, $other:expr, $field:ident) => {
402 if let Some(other_vec) = $other.$field.take() {
403 if let Some(self_vec) = $self.$field.as_mut() {
404 self_vec.extend(other_vec);
405 } else {
406 $self.$field = Some(other_vec);
407 }
408 }
409 };
410}