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 cm_types::BorrowedName;
13
14use crate::OneOrMany;
15
16#[derive(Debug, Clone, PartialEq, Eq, Hash)]
17pub struct Origin {
18 pub file: Arc<PathBuf>,
19 pub location: Location,
20}
21
22#[derive(Debug, Clone, PartialEq)]
23pub struct ContextSpanned<T> {
24 pub value: T,
25 pub origin: Origin,
26}
27
28pub trait Hydrate {
31 type Output;
32
33 fn hydrate(self, file: &Arc<PathBuf>, buffer: &String) -> Self::Output;
34}
35
36pub fn hydrate_list<P, C>(
37 raw_list: Option<Spanned<Vec<Spanned<P>>>>,
38 file: &Arc<PathBuf>,
39 buffer: &String,
40) -> Option<Vec<ContextSpanned<C>>>
41where
42 P: Hydrate<Output = C>,
43{
44 raw_list.map(|spanned_vec| {
45 spanned_vec
46 .into_inner()
47 .into_iter()
48 .map(|spanned_item| {
49 let span = spanned_item.span();
50 let location = byte_index_to_location(buffer, span.0);
51 let parsed_item = spanned_item.into_inner();
52
53 let context_item = parsed_item.hydrate(file, buffer);
54
55 ContextSpanned {
56 value: context_item,
57 origin: Origin { file: file.clone(), location },
58 }
59 })
60 .collect()
61 })
62}
63
64pub fn hydrate_required<P, C>(
65 spanned: Spanned<P>,
66 file: &Arc<PathBuf>,
67 buffer: &String,
68) -> ContextSpanned<C>
69where
70 P: Hydrate<Output = C>,
71{
72 let span = spanned.span();
73 let location = byte_index_to_location(buffer, span.0);
74 let parsed_value = spanned.into_inner();
75 ContextSpanned {
76 value: parsed_value.hydrate(file, buffer),
77 origin: Origin { file: file.clone(), location },
78 }
79}
80
81pub fn hydrate_simple<T>(
82 spanned: Spanned<T>,
83 file: &Arc<PathBuf>,
84 buffer: &String,
85) -> ContextSpanned<T> {
86 let span = spanned.span();
87 let location = byte_index_to_location(buffer, span.0);
88 ContextSpanned { value: spanned.into_inner(), origin: Origin { file: file.clone(), location } }
89}
90
91pub fn hydrate_opt<P, C>(
92 opt_spanned: Option<Spanned<P>>,
93 file: &Arc<PathBuf>,
94 buffer: &String,
95) -> Option<ContextSpanned<C>>
96where
97 P: Hydrate<Output = C>,
98{
99 opt_spanned.map(|s| hydrate_required(s, file, buffer))
100}
101
102pub fn hydrate_opt_simple<T>(
103 opt_spanned: Option<Spanned<T>>,
104 file: &Arc<PathBuf>,
105 buffer: &String,
106) -> Option<ContextSpanned<T>> {
107 opt_spanned.map(|s| hydrate_simple(s, file, buffer))
108}
109
110pub fn option_one_or_many_as_ref_context<T, S: ?Sized>(
111 o: &Option<ContextSpanned<OneOrMany<T>>>,
112) -> Option<ContextSpanned<OneOrMany<&S>>>
113where
114 T: AsRef<S>,
115{
116 o.as_ref().map(|spanned| ContextSpanned {
117 origin: spanned.origin.clone(),
118 value: match &spanned.value {
119 OneOrMany::One(item) => OneOrMany::One(item.as_ref()),
120 OneOrMany::Many(items) => {
121 OneOrMany::Many(items.iter().map(|item| item.as_ref()).collect())
122 }
123 },
124 })
125}
126
127pub trait ContextPathClause {
128 fn path(&self) -> Option<&ContextSpanned<Path>>;
129}
130
131pub trait ContextCapabilityClause {
132 fn service(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>>;
133 fn protocol(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>>;
134 fn directory(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>>;
135 fn storage(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>>;
136 fn runner(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>>;
137 fn resolver(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>>;
138 fn dictionary(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>>;
139 fn config(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>>;
140 fn event_stream(&self) -> Option<ContextSpanned<OneOrMany<&BorrowedName>>>;
141
142 fn capability_type(&self, origin: Option<Origin>) -> Result<&'static str, Error> {
147 let mut types = Vec::new();
148 if self.service().is_some() {
149 types.push("service");
150 }
151 if self.protocol().is_some() {
152 types.push("protocol");
153 }
154 if self.directory().is_some() {
155 types.push("directory");
156 }
157 if self.storage().is_some() {
158 types.push("storage");
159 }
160 if self.event_stream().is_some() {
161 types.push("event_stream");
162 }
163 if self.runner().is_some() {
164 types.push("runner");
165 }
166 if self.config().is_some() {
167 types.push("config");
168 }
169 if self.resolver().is_some() {
170 types.push("resolver");
171 }
172 if self.dictionary().is_some() {
173 types.push("dictionary");
174 }
175 match types.len() {
176 0 => {
177 let supported_keywords = self
178 .supported()
179 .into_iter()
180 .map(|k| format!("\"{}\"", k))
181 .collect::<Vec<_>>()
182 .join(", ");
183 Err(Error::validate_context(
184 format!(
185 "`{}` declaration is missing a capability keyword, one of: {}",
186 self.decl_type(),
187 supported_keywords,
188 ),
189 origin,
190 ))
191 }
192 1 => Ok(types[0]),
193 _ => Err(Error::validate_context(
194 format!(
195 "{} declaration has multiple capability types defined: {:?}",
196 self.decl_type(),
197 types
198 ),
199 origin,
200 )),
201 }
202 }
203
204 fn names(&self) -> Vec<&BorrowedName> {
207 let res = vec![
208 self.service(),
209 self.protocol(),
210 self.directory(),
211 self.storage(),
212 self.runner(),
213 self.config(),
214 self.resolver(),
215 self.event_stream(),
216 self.dictionary(),
217 ];
218 res.into_iter()
219 .map(|o| {
220 o.map(|o| o.value.into_iter().collect::<Vec<&BorrowedName>>()).unwrap_or(vec![])
221 })
222 .flatten()
223 .collect()
224 }
225
226 fn are_many_names_allowed(&self) -> bool;
228
229 fn decl_type(&self) -> &'static str;
230 fn supported(&self) -> &[&'static str];
231}