Skip to main content

cm_rust/
use.rs

1// Copyright 2026 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 cm_rust_derive::{FidlDecl, UseDeclCommon};
6use cm_types::{BorrowedSeparatedPath, Name, Path, RelativePath};
7use fidl_fuchsia_component_decl as fdecl;
8use fidl_fuchsia_io as fio;
9use from_enum::FromEnum;
10use std::collections::BTreeMap;
11use std::fmt;
12use std::hash::Hash;
13use std::sync::LazyLock;
14
15use crate::{
16    Availability, ConfigValue, ConfigValueType, DependencyType, DictionaryValue, EventScope,
17    FidlIntoNative, NativeIntoFidl, SourceName, SourcePath,
18};
19
20#[cfg(fuchsia_api_level_at_least = "29")]
21pub use cm_types::HandleType;
22
23#[cfg(feature = "serde")]
24use crate::serde_ext;
25
26#[cfg(feature = "serde")]
27use serde::{Deserialize, Serialize};
28
29#[cfg_attr(
30    feature = "serde",
31    derive(Deserialize, Serialize),
32    serde(tag = "type", rename_all = "snake_case")
33)]
34#[derive(FidlDecl, FromEnum, Debug, Clone, PartialEq, Eq)]
35#[fidl_decl(fidl_union = "fdecl::Use")]
36pub enum UseDecl {
37    Service(UseServiceDecl),
38    Protocol(UseProtocolDecl),
39    Directory(UseDirectoryDecl),
40    Storage(UseStorageDecl),
41    EventStream(Box<UseEventStreamDecl>),
42    #[cfg(fuchsia_api_level_at_least = "HEAD")]
43    Runner(UseRunnerDecl),
44    Config(Box<UseConfigurationDecl>),
45    #[cfg(fuchsia_api_level_at_least = "29")]
46    Dictionary(UseDictionaryDecl),
47}
48
49#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
50#[derive(FidlDecl, UseDeclCommon, Debug, Clone, PartialEq, Eq)]
51#[fidl_decl(fidl_table = "fdecl::UseService", source_path = "dictionary")]
52pub struct UseServiceDecl {
53    pub source: UseSource,
54    pub source_name: Name,
55    #[fidl_decl(default_preserve_none)]
56    pub source_dictionary: RelativePath,
57    pub target_path: Path,
58    pub dependency_type: DependencyType,
59    #[fidl_decl(default)]
60    pub availability: Availability,
61}
62
63#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
64#[derive(FidlDecl, UseDeclCommon, Debug, Clone, PartialEq, Eq)]
65#[fidl_decl(fidl_table = "fdecl::UseProtocol", source_path = "dictionary")]
66pub struct UseProtocolDecl {
67    pub source: UseSource,
68    pub source_name: Name,
69    #[fidl_decl(default_preserve_none)]
70    pub source_dictionary: RelativePath,
71    pub target_path: Option<Path>,
72    #[cfg(fuchsia_api_level_at_least = "29")]
73    pub numbered_handle: Option<HandleType>,
74    pub dependency_type: DependencyType,
75    #[fidl_decl(default)]
76    pub availability: Availability,
77}
78
79#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
80#[derive(FidlDecl, UseDeclCommon, Debug, Clone, PartialEq, Eq)]
81#[fidl_decl(fidl_table = "fdecl::UseDirectory", source_path = "dictionary")]
82pub struct UseDirectoryDecl {
83    pub source: UseSource,
84    pub source_name: Name,
85    #[fidl_decl(default_preserve_none)]
86    pub source_dictionary: RelativePath,
87    pub target_path: Path,
88
89    #[cfg_attr(
90        feature = "serde",
91        serde(
92            deserialize_with = "serde_ext::deserialize_fio_operations",
93            serialize_with = "serde_ext::serialize_fio_operations"
94        )
95    )]
96    pub rights: fio::Operations,
97
98    #[fidl_decl(default_preserve_none)]
99    pub subdir: RelativePath,
100    pub dependency_type: DependencyType,
101    #[fidl_decl(default)]
102    pub availability: Availability,
103}
104
105#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
106#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
107#[fidl_decl(fidl_table = "fdecl::UseStorage", source_path = "name_only")]
108pub struct UseStorageDecl {
109    pub source_name: Name,
110    pub target_path: Path,
111    #[fidl_decl(default)]
112    pub availability: Availability,
113}
114
115impl SourceName for UseStorageDecl {
116    fn source_name(&self) -> &Name {
117        &self.source_name
118    }
119}
120
121impl UseDeclCommon for UseStorageDecl {
122    fn source(&self) -> &UseSource {
123        &UseSource::Parent
124    }
125
126    fn availability(&self) -> &Availability {
127        &self.availability
128    }
129}
130
131#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
132#[derive(FidlDecl, UseDeclCommon, Debug, Clone, PartialEq, Eq, Hash)]
133#[fidl_decl(fidl_table = "fdecl::UseEventStream", source_path = "name_only")]
134pub struct UseEventStreamDecl {
135    pub source_name: Name,
136    pub source: UseSource,
137    pub scope: Option<Box<[EventScope]>>,
138    pub target_path: Path,
139    pub filter: Option<BTreeMap<String, DictionaryValue>>,
140    #[fidl_decl(default)]
141    pub availability: Availability,
142}
143
144#[cfg(fuchsia_api_level_at_least = "HEAD")]
145#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
146#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
147#[fidl_decl(fidl_table = "fdecl::UseRunner", source_path = "dictionary")]
148pub struct UseRunnerDecl {
149    pub source: UseSource,
150    pub source_name: Name,
151    #[fidl_decl(default_preserve_none)]
152    pub source_dictionary: RelativePath,
153}
154
155#[cfg(fuchsia_api_level_at_least = "29")]
156#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
157#[derive(FidlDecl, UseDeclCommon, Debug, Clone, PartialEq, Eq)]
158#[fidl_decl(fidl_table = "fdecl::UseDictionary", source_path = "dictionary")]
159pub struct UseDictionaryDecl {
160    pub source: UseSource,
161    pub source_name: Name,
162    #[fidl_decl(default_preserve_none)]
163    pub source_dictionary: RelativePath,
164    pub target_path: Path,
165    pub dependency_type: DependencyType,
166    #[fidl_decl(default)]
167    pub availability: Availability,
168}
169
170#[cfg(fuchsia_api_level_at_least = "HEAD")]
171impl SourceName for UseRunnerDecl {
172    fn source_name(&self) -> &Name {
173        &self.source_name
174    }
175}
176
177#[cfg(fuchsia_api_level_at_least = "HEAD")]
178impl UseDeclCommon for UseRunnerDecl {
179    fn source(&self) -> &UseSource {
180        &self.source
181    }
182
183    fn availability(&self) -> &Availability {
184        &Availability::Required
185    }
186}
187
188#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
189#[derive(FidlDecl, UseDeclCommon, Debug, Clone, PartialEq, Eq)]
190#[fidl_decl(fidl_table = "fdecl::UseConfiguration", source_path = "dictionary")]
191pub struct UseConfigurationDecl {
192    pub source: UseSource,
193    pub source_name: Name,
194    #[fidl_decl(default_preserve_none)]
195    pub source_dictionary: RelativePath,
196    pub target_name: Name,
197    #[fidl_decl(default)]
198    pub availability: Availability,
199    pub type_: ConfigValueType,
200    pub default: Option<ConfigValue>,
201}
202
203impl UseDeclCommon for UseDecl {
204    fn source(&self) -> &UseSource {
205        match &self {
206            UseDecl::Service(u) => u.source(),
207            UseDecl::Protocol(u) => u.source(),
208            UseDecl::Directory(u) => u.source(),
209            UseDecl::Storage(u) => u.source(),
210            UseDecl::EventStream(u) => u.source(),
211            #[cfg(fuchsia_api_level_at_least = "HEAD")]
212            UseDecl::Runner(u) => u.source(),
213            UseDecl::Config(u) => u.source(),
214            #[cfg(fuchsia_api_level_at_least = "29")]
215            UseDecl::Dictionary(u) => u.source(),
216        }
217    }
218
219    fn availability(&self) -> &Availability {
220        match &self {
221            UseDecl::Service(u) => u.availability(),
222            UseDecl::Protocol(u) => u.availability(),
223            UseDecl::Directory(u) => u.availability(),
224            UseDecl::Storage(u) => u.availability(),
225            UseDecl::EventStream(u) => u.availability(),
226            #[cfg(fuchsia_api_level_at_least = "HEAD")]
227            UseDecl::Runner(u) => u.availability(),
228            UseDecl::Config(u) => u.availability(),
229            #[cfg(fuchsia_api_level_at_least = "29")]
230            UseDecl::Dictionary(u) => u.availability(),
231        }
232    }
233}
234
235/// The common properties of a [Use](fdecl::Use) declaration.
236pub trait UseDeclCommon: SourceName + SourcePath + Send + Sync {
237    fn source(&self) -> &UseSource;
238    fn availability(&self) -> &Availability;
239}
240
241#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
242#[derive(Debug, Clone, PartialEq, Eq, Hash)]
243pub enum UseSource {
244    Parent,
245    Framework,
246    Debug,
247    Self_,
248    Capability(Name),
249    Child(Name),
250    Collection(Name),
251    #[cfg(fuchsia_api_level_at_least = "HEAD")]
252    Environment,
253}
254
255impl std::fmt::Display for UseSource {
256    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
257        match self {
258            Self::Framework => write!(f, "framework"),
259            Self::Parent => write!(f, "parent"),
260            Self::Debug => write!(f, "debug environment"),
261            Self::Self_ => write!(f, "self"),
262            Self::Capability(c) => write!(f, "capability `{}`", c),
263            Self::Child(c) => write!(f, "child `#{}`", c),
264            Self::Collection(c) => write!(f, "collection `#{}`", c),
265            #[cfg(fuchsia_api_level_at_least = "HEAD")]
266            Self::Environment => write!(f, "environment"),
267        }
268    }
269}
270
271impl FidlIntoNative<UseSource> for fdecl::Ref {
272    fn fidl_into_native(self) -> UseSource {
273        match self {
274            fdecl::Ref::Parent(_) => UseSource::Parent,
275            fdecl::Ref::Framework(_) => UseSource::Framework,
276            fdecl::Ref::Debug(_) => UseSource::Debug,
277            fdecl::Ref::Self_(_) => UseSource::Self_,
278            // cm_fidl_validator should have already validated this
279            fdecl::Ref::Capability(c) => UseSource::Capability(c.name.parse().unwrap()),
280            fdecl::Ref::Child(c) => UseSource::Child(c.name.parse().unwrap()),
281            fdecl::Ref::Collection(c) => UseSource::Collection(c.name.parse().unwrap()),
282            #[cfg(fuchsia_api_level_at_least = "HEAD")]
283            fdecl::Ref::Environment(_) => UseSource::Environment,
284            _ => panic!("invalid UseSource variant"),
285        }
286    }
287}
288
289impl NativeIntoFidl<fdecl::Ref> for UseSource {
290    fn native_into_fidl(self) -> fdecl::Ref {
291        match self {
292            UseSource::Parent => fdecl::Ref::Parent(fdecl::ParentRef {}),
293            UseSource::Framework => fdecl::Ref::Framework(fdecl::FrameworkRef {}),
294            UseSource::Debug => fdecl::Ref::Debug(fdecl::DebugRef {}),
295            UseSource::Self_ => fdecl::Ref::Self_(fdecl::SelfRef {}),
296            UseSource::Capability(name) => {
297                fdecl::Ref::Capability(fdecl::CapabilityRef { name: name.to_string() })
298            }
299            UseSource::Child(name) => {
300                fdecl::Ref::Child(fdecl::ChildRef { name: name.to_string(), collection: None })
301            }
302            UseSource::Collection(name) => {
303                fdecl::Ref::Collection(fdecl::CollectionRef { name: name.to_string() })
304            }
305            #[cfg(fuchsia_api_level_at_least = "HEAD")]
306            UseSource::Environment => fdecl::Ref::Environment(fdecl::EnvironmentRef {}),
307        }
308    }
309}
310
311#[cfg(fuchsia_api_level_at_least = "29")]
312impl FidlIntoNative<HandleType> for u8 {
313    fn fidl_into_native(self) -> HandleType {
314        self.into()
315    }
316}
317
318#[cfg(fuchsia_api_level_at_least = "29")]
319impl NativeIntoFidl<u8> for HandleType {
320    fn native_into_fidl(self) -> u8 {
321        self.into()
322    }
323}