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