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