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