Skip to main content

cml/types/
common.rs

1// Copyright 2025 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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
68/// Hydrate is used to translate a type to a
69/// Result<ContextSpanned> type. The ContextSpanned type is used by validation.
70///
71/// It is possible to error when merging if a field is defined as multiple,
72/// incompatible data structures.
73pub 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    // /// Returns the name of the capability for display purposes.
178    // /// If `service()` returns `Some`, the capability name must be "service", etc.
179    // ///
180    // /// Returns an error if the capability name is not set, or if there is more than one.
181    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    /// Returns the names of the capabilities in this clause, wrapped in ContextSpanned.
240    /// This allows the caller to know the file source of every individual name.
241    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                        // n is &&BorrowedName. We deref once to get &BorrowedName,
246                        // then .to_owned() converts it to Name.
247                        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        // Collect names from all possible fields
263        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    /// Sets the names for this capability, preserving origin information.
277    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    /// Returns true if this capability type allows the ::Many variant of OneOrMany.
314    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}