cml/types/
collection.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 crate::Error;
6use crate::types::common::*;
7use crate::types::environment::EnvironmentRef;
8pub use cm_types::{AllowedOffers, Durability, Name};
9use json_spanned_value::Spanned;
10use reference_doc::ReferenceDoc;
11use serde::{Deserialize, Serialize};
12use std::path::PathBuf;
13use std::sync::Arc;
14
15#[derive(Deserialize, Debug, PartialEq, ReferenceDoc, Serialize)]
16#[serde(deny_unknown_fields)]
17#[reference_doc(fields_as = "list", top_level_doc_after_fields)]
18/// Example:
19///
20/// ```json5
21/// collections: [
22///     {
23///         name: "tests",
24///         durability: "transient",
25///     },
26/// ],
27/// ```
28pub struct Collection {
29    /// The name of the component collection, which is a string of one or
30    /// more of the following characters: `a-z`, `0-9`, `_`, `.`, `-`. The name
31    /// identifies this collection when used in a [reference](#references).
32    pub name: Name,
33
34    /// The duration of child component instances in the collection.
35    /// - `transient`: The instance exists until its parent is stopped or it is
36    ///     explicitly destroyed.
37    /// - `single_run`: The instance is started when it is created, and destroyed
38    ///     when it is stopped.
39    pub durability: Durability,
40
41    /// If present, the environment that will be
42    /// assigned to instances in this collection, one of
43    /// [`environments`](#environments). If omitted, instances in this collection
44    /// will inherit the same environment assigned to this component.
45    pub environment: Option<EnvironmentRef>,
46
47    /// Constraints on the dynamic offers that target the components in this collection.
48    /// Dynamic offers are specified when calling `fuchsia.component.Realm/CreateChild`.
49    /// - `static_only`: Only those specified in this `.cml` file. No dynamic offers.
50    ///     This is the default.
51    /// - `static_and_dynamic`: Both static offers and those specified at runtime
52    ///     with `CreateChild` are allowed.
53    pub allowed_offers: Option<AllowedOffers>,
54
55    /// Allow child names up to 1024 characters long instead of the usual 255 character limit.
56    /// Default is false.
57    pub allow_long_names: Option<bool>,
58
59    /// If set to `true`, the data in isolated storage used by dynamic child instances and
60    /// their descendants will persist after the instances are destroyed. A new child instance
61    /// created with the same name will share the same storage path as the previous instance.
62    pub persistent_storage: Option<bool>,
63}
64
65#[derive(Deserialize, Debug, PartialEq, Clone)]
66#[serde(deny_unknown_fields)]
67pub struct ParsedCollection {
68    pub name: Spanned<Name>,
69    pub durability: Spanned<Durability>,
70    pub environment: Option<Spanned<EnvironmentRef>>,
71    pub allowed_offers: Option<Spanned<AllowedOffers>>,
72    pub allow_long_names: Option<Spanned<bool>>,
73    pub persistent_storage: Option<Spanned<bool>>,
74}
75
76#[derive(Debug, Clone)]
77pub struct ContextCollection {
78    pub name: ContextSpanned<Name>,
79    pub durability: ContextSpanned<Durability>,
80    pub environment: Option<ContextSpanned<EnvironmentRef>>,
81    pub allowed_offers: Option<ContextSpanned<AllowedOffers>>,
82    pub allow_long_names: Option<ContextSpanned<bool>>,
83    pub persistent_storage: Option<ContextSpanned<bool>>,
84}
85
86impl PartialEq for ContextCollection {
87    fn eq(&self, other: &Self) -> bool {
88        macro_rules! cmp {
89            ($field:ident) => {
90                match (&self.$field, &other.$field) {
91                    (Some(a), Some(b)) => a.value == b.value,
92                    (None, None) => true,
93                    _ => false,
94                }
95            };
96        }
97
98        self.name.value == other.name.value
99            && self.durability.value == other.durability.value
100            && cmp!(environment)
101            && cmp!(allowed_offers)
102            && cmp!(allow_long_names)
103            && cmp!(persistent_storage)
104    }
105}
106
107impl Eq for ContextCollection {}
108
109impl Hydrate for ParsedCollection {
110    type Output = ContextCollection;
111
112    fn hydrate(self, file: &Arc<PathBuf>, buffer: &String) -> Result<Self::Output, Error> {
113        Ok(ContextCollection {
114            name: hydrate_simple(self.name, file, buffer),
115            durability: hydrate_simple(self.durability, file, buffer),
116            environment: hydrate_opt_simple(self.environment, file, buffer),
117            allowed_offers: hydrate_opt_simple(self.allowed_offers, file, buffer),
118            allow_long_names: hydrate_opt_simple(self.allow_long_names, file, buffer),
119            persistent_storage: hydrate_opt_simple(self.persistent_storage, file, buffer),
120        })
121    }
122}