Skip to main content

cm_rust/
offer.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, OfferDeclCommon, OfferDeclCommonNoAvailability};
6use cm_types::{BorrowedSeparatedPath, Name, RelativePath};
7use fidl_fuchsia_component_decl as fdecl;
8use fidl_fuchsia_io as fio;
9use from_enum::FromEnum;
10use std::fmt;
11use std::hash::Hash;
12use std::sync::LazyLock;
13
14use crate::{
15    Availability, CapabilityTypeName, ChildRef, DependencyType, EventScope, FidlIntoNative,
16    NameMapping, NativeIntoFidl, SourceName, SourcePath,
17};
18
19#[cfg(feature = "serde")]
20use crate::serde_ext;
21
22#[cfg(feature = "serde")]
23use serde::{Deserialize, Serialize};
24
25#[cfg_attr(
26    feature = "serde",
27    derive(Deserialize, Serialize),
28    serde(tag = "type", rename_all = "snake_case")
29)]
30#[derive(FidlDecl, FromEnum, Debug, Clone, PartialEq, Eq)]
31#[fidl_decl(fidl_union = "fdecl::Offer")]
32pub enum OfferDecl {
33    Service(OfferServiceDecl),
34    Protocol(OfferProtocolDecl),
35    Directory(OfferDirectoryDecl),
36    Storage(OfferStorageDecl),
37    Runner(OfferRunnerDecl),
38    Resolver(OfferResolverDecl),
39    EventStream(OfferEventStreamDecl),
40    Dictionary(OfferDictionaryDecl),
41    Config(OfferConfigurationDecl),
42}
43
44#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
45#[derive(FidlDecl, OfferDeclCommon, Debug, Clone, PartialEq, Eq)]
46#[fidl_decl(fidl_table = "fdecl::OfferEventStream", source_path = "name_only")]
47pub struct OfferEventStreamDecl {
48    pub source: OfferSource,
49    pub scope: Option<Box<[EventScope]>>,
50    pub source_name: Name,
51    pub target: OfferTarget,
52    pub target_name: Name,
53    #[fidl_decl(default)]
54    pub availability: Availability,
55}
56
57#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
58#[derive(FidlDecl, OfferDeclCommon, Debug, Clone, PartialEq, Eq)]
59#[fidl_decl(fidl_table = "fdecl::OfferService", source_path = "dictionary")]
60pub struct OfferServiceDecl {
61    pub source: OfferSource,
62    pub source_name: Name,
63    #[fidl_decl(default_preserve_none)]
64    pub source_dictionary: RelativePath,
65    pub target: OfferTarget,
66    pub target_name: Name,
67    pub source_instance_filter: Option<Box<[Name]>>,
68    pub renamed_instances: Option<Box<[NameMapping]>>,
69    #[fidl_decl(default)]
70    pub availability: Availability,
71    #[cfg(fuchsia_api_level_at_least = "HEAD")]
72    #[fidl_decl(default)]
73    pub dependency_type: DependencyType,
74}
75
76#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
77#[derive(FidlDecl, OfferDeclCommon, Debug, Clone, PartialEq, Eq)]
78#[fidl_decl(fidl_table = "fdecl::OfferProtocol", source_path = "dictionary")]
79pub struct OfferProtocolDecl {
80    pub source: OfferSource,
81    pub source_name: Name,
82    #[fidl_decl(default_preserve_none)]
83    pub source_dictionary: RelativePath,
84    pub target: OfferTarget,
85    pub target_name: Name,
86    pub dependency_type: DependencyType,
87    #[fidl_decl(default)]
88    pub availability: Availability,
89}
90
91#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
92#[derive(FidlDecl, OfferDeclCommon, Debug, Clone, PartialEq, Eq)]
93#[fidl_decl(fidl_table = "fdecl::OfferDirectory", source_path = "dictionary")]
94pub struct OfferDirectoryDecl {
95    pub source: OfferSource,
96    pub source_name: Name,
97    #[fidl_decl(default_preserve_none)]
98    pub source_dictionary: RelativePath,
99    pub target: OfferTarget,
100    pub target_name: Name,
101    pub dependency_type: DependencyType,
102
103    #[cfg_attr(
104        feature = "serde",
105        serde(
106            deserialize_with = "serde_ext::deserialize_opt_fio_operations",
107            serialize_with = "serde_ext::serialize_opt_fio_operations"
108        )
109    )]
110    pub rights: Option<fio::Operations>,
111
112    #[fidl_decl(default_preserve_none)]
113    pub subdir: RelativePath,
114    #[fidl_decl(default)]
115    pub availability: Availability,
116}
117
118#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
119#[derive(FidlDecl, OfferDeclCommon, Debug, Clone, PartialEq, Eq)]
120#[fidl_decl(fidl_table = "fdecl::OfferStorage", source_path = "name_only")]
121pub struct OfferStorageDecl {
122    pub source: OfferSource,
123    pub source_name: Name,
124    pub target: OfferTarget,
125    pub target_name: Name,
126    #[fidl_decl(default)]
127    pub availability: Availability,
128}
129
130#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
131#[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
132#[fidl_decl(fidl_table = "fdecl::OfferRunner", source_path = "dictionary")]
133pub struct OfferRunnerDecl {
134    pub source: OfferSource,
135    pub source_name: Name,
136    #[fidl_decl(default_preserve_none)]
137    pub source_dictionary: RelativePath,
138    pub target: OfferTarget,
139    pub target_name: Name,
140}
141
142#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
143#[derive(FidlDecl, OfferDeclCommonNoAvailability, Debug, Clone, PartialEq, Eq)]
144#[fidl_decl(fidl_table = "fdecl::OfferResolver", source_path = "dictionary")]
145pub struct OfferResolverDecl {
146    pub source: OfferSource,
147    pub source_name: Name,
148    #[fidl_decl(default_preserve_none)]
149    pub source_dictionary: RelativePath,
150    pub target: OfferTarget,
151    pub target_name: Name,
152}
153
154#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
155#[derive(FidlDecl, OfferDeclCommon, Debug, Clone, PartialEq, Eq)]
156#[fidl_decl(fidl_table = "fdecl::OfferDictionary", source_path = "dictionary")]
157pub struct OfferDictionaryDecl {
158    pub source: OfferSource,
159    pub source_name: Name,
160    #[fidl_decl(default_preserve_none)]
161    pub source_dictionary: RelativePath,
162    pub target: OfferTarget,
163    pub target_name: Name,
164    pub dependency_type: DependencyType,
165    #[fidl_decl(default)]
166    pub availability: Availability,
167}
168
169#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
170#[derive(FidlDecl, OfferDeclCommon, Debug, Clone, PartialEq, Eq)]
171#[fidl_decl(fidl_table = "fdecl::OfferConfiguration", source_path = "dictionary")]
172pub struct OfferConfigurationDecl {
173    pub source: OfferSource,
174    pub source_name: Name,
175    #[fidl_decl(default_preserve_none)]
176    pub source_dictionary: RelativePath,
177    pub target: OfferTarget,
178    pub target_name: Name,
179    #[fidl_decl(default)]
180    pub availability: Availability,
181}
182
183impl SourceName for OfferDecl {
184    fn source_name(&self) -> &Name {
185        match &self {
186            OfferDecl::Service(o) => o.source_name(),
187            OfferDecl::Protocol(o) => o.source_name(),
188            OfferDecl::Directory(o) => o.source_name(),
189            OfferDecl::Storage(o) => o.source_name(),
190            OfferDecl::Runner(o) => o.source_name(),
191            OfferDecl::Resolver(o) => o.source_name(),
192            OfferDecl::EventStream(o) => o.source_name(),
193            OfferDecl::Dictionary(o) => o.source_name(),
194            OfferDecl::Config(o) => o.source_name(),
195        }
196    }
197}
198
199impl SourcePath for OfferDecl {
200    fn source_path(&self) -> BorrowedSeparatedPath<'_> {
201        match &self {
202            OfferDecl::Service(o) => o.source_path(),
203            OfferDecl::Protocol(o) => o.source_path(),
204            OfferDecl::Directory(o) => o.source_path(),
205            OfferDecl::Storage(o) => o.source_path(),
206            OfferDecl::Runner(o) => o.source_path(),
207            OfferDecl::Resolver(o) => o.source_path(),
208            OfferDecl::EventStream(o) => o.source_path(),
209            OfferDecl::Dictionary(o) => o.source_path(),
210            OfferDecl::Config(o) => o.source_path(),
211        }
212    }
213}
214
215impl OfferDeclCommon for OfferDecl {
216    fn target_name(&self) -> &Name {
217        match &self {
218            OfferDecl::Service(o) => o.target_name(),
219            OfferDecl::Protocol(o) => o.target_name(),
220            OfferDecl::Directory(o) => o.target_name(),
221            OfferDecl::Storage(o) => o.target_name(),
222            OfferDecl::Runner(o) => o.target_name(),
223            OfferDecl::Resolver(o) => o.target_name(),
224            OfferDecl::EventStream(o) => o.target_name(),
225            OfferDecl::Dictionary(o) => o.target_name(),
226            OfferDecl::Config(o) => o.target_name(),
227        }
228    }
229
230    fn target(&self) -> &OfferTarget {
231        match &self {
232            OfferDecl::Service(o) => o.target(),
233            OfferDecl::Protocol(o) => o.target(),
234            OfferDecl::Directory(o) => o.target(),
235            OfferDecl::Storage(o) => o.target(),
236            OfferDecl::Runner(o) => o.target(),
237            OfferDecl::Resolver(o) => o.target(),
238            OfferDecl::EventStream(o) => o.target(),
239            OfferDecl::Dictionary(o) => o.target(),
240            OfferDecl::Config(o) => o.target(),
241        }
242    }
243
244    fn source(&self) -> &OfferSource {
245        match &self {
246            OfferDecl::Service(o) => o.source(),
247            OfferDecl::Protocol(o) => o.source(),
248            OfferDecl::Directory(o) => o.source(),
249            OfferDecl::Storage(o) => o.source(),
250            OfferDecl::Runner(o) => o.source(),
251            OfferDecl::Resolver(o) => o.source(),
252            OfferDecl::EventStream(o) => o.source(),
253            OfferDecl::Dictionary(o) => o.source(),
254            OfferDecl::Config(o) => o.source(),
255        }
256    }
257
258    fn availability(&self) -> &Availability {
259        match &self {
260            OfferDecl::Service(o) => o.availability(),
261            OfferDecl::Protocol(o) => o.availability(),
262            OfferDecl::Directory(o) => o.availability(),
263            OfferDecl::Storage(o) => o.availability(),
264            OfferDecl::Runner(o) => o.availability(),
265            OfferDecl::Resolver(o) => o.availability(),
266            OfferDecl::EventStream(o) => o.availability(),
267            OfferDecl::Dictionary(o) => o.availability(),
268            OfferDecl::Config(o) => o.availability(),
269        }
270    }
271}
272
273impl SourceName for OfferRunnerDecl {
274    fn source_name(&self) -> &Name {
275        &self.source_name
276    }
277}
278
279impl OfferDeclCommon for OfferRunnerDecl {
280    fn target_name(&self) -> &Name {
281        &self.target_name
282    }
283
284    fn target(&self) -> &OfferTarget {
285        &self.target
286    }
287
288    fn source(&self) -> &OfferSource {
289        &self.source
290    }
291
292    fn availability(&self) -> &Availability {
293        &Availability::Required
294    }
295}
296
297/// The common properties of an [Offer](fdecl::Offer) declaration.
298pub trait OfferDeclCommon: SourceName + SourcePath + fmt::Debug + Send + Sync {
299    fn target_name(&self) -> &Name;
300    fn target(&self) -> &OfferTarget;
301    fn source(&self) -> &OfferSource;
302    fn availability(&self) -> &Availability;
303}
304
305impl From<&OfferDecl> for CapabilityTypeName {
306    fn from(offer_decl: &OfferDecl) -> Self {
307        match offer_decl {
308            OfferDecl::Service(_) => Self::Service,
309            OfferDecl::Protocol(_) => Self::Protocol,
310            OfferDecl::Directory(_) => Self::Directory,
311            OfferDecl::Storage(_) => Self::Storage,
312            OfferDecl::Runner(_) => Self::Runner,
313            OfferDecl::Resolver(_) => Self::Resolver,
314            OfferDecl::EventStream(_) => Self::EventStream,
315            OfferDecl::Dictionary(_) => Self::Dictionary,
316            OfferDecl::Config(_) => Self::Config,
317        }
318    }
319}
320
321#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
322#[derive(Debug, Clone, PartialEq, Eq)]
323pub enum OfferSource {
324    Framework,
325    Parent,
326    Child(ChildRef),
327    Collection(Name),
328    Self_,
329    Capability(Name),
330    Void,
331}
332
333impl std::fmt::Display for OfferSource {
334    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
335        match self {
336            Self::Framework => write!(f, "framework"),
337            Self::Parent => write!(f, "parent"),
338            Self::Child(c) => write!(f, "child `#{}`", c),
339            Self::Collection(c) => write!(f, "collection `#{}`", c),
340            Self::Self_ => write!(f, "self"),
341            Self::Capability(c) => write!(f, "capability `{}`", c),
342            Self::Void => write!(f, "void"),
343        }
344    }
345}
346
347impl FidlIntoNative<OfferSource> for fdecl::Ref {
348    fn fidl_into_native(self) -> OfferSource {
349        match self {
350            fdecl::Ref::Parent(_) => OfferSource::Parent,
351            fdecl::Ref::Self_(_) => OfferSource::Self_,
352            fdecl::Ref::Child(c) => OfferSource::Child(c.fidl_into_native()),
353            // cm_fidl_validator should have already validated this
354            fdecl::Ref::Collection(c) => OfferSource::Collection(c.name.parse().unwrap()),
355            fdecl::Ref::Framework(_) => OfferSource::Framework,
356            // cm_fidl_validator should have already validated this
357            fdecl::Ref::Capability(c) => OfferSource::Capability(c.name.parse().unwrap()),
358            fdecl::Ref::VoidType(_) => OfferSource::Void,
359            _ => panic!("invalid OfferSource variant"),
360        }
361    }
362}
363
364impl NativeIntoFidl<fdecl::Ref> for OfferSource {
365    fn native_into_fidl(self) -> fdecl::Ref {
366        match self {
367            OfferSource::Parent => fdecl::Ref::Parent(fdecl::ParentRef {}),
368            OfferSource::Self_ => fdecl::Ref::Self_(fdecl::SelfRef {}),
369            OfferSource::Child(c) => fdecl::Ref::Child(c.native_into_fidl()),
370            OfferSource::Collection(name) => {
371                fdecl::Ref::Collection(fdecl::CollectionRef { name: name.native_into_fidl() })
372            }
373            OfferSource::Framework => fdecl::Ref::Framework(fdecl::FrameworkRef {}),
374            OfferSource::Capability(name) => {
375                fdecl::Ref::Capability(fdecl::CapabilityRef { name: name.to_string() })
376            }
377            OfferSource::Void => fdecl::Ref::VoidType(fdecl::VoidRef {}),
378        }
379    }
380}
381
382#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
383#[derive(Debug, Clone, PartialEq, Eq, Hash)]
384pub enum OfferTarget {
385    Child(ChildRef),
386    Collection(Name),
387    Capability(Name),
388}
389
390impl std::fmt::Display for OfferTarget {
391    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
392        match self {
393            Self::Child(c) => write!(f, "child `#{}`", c),
394            Self::Collection(c) => write!(f, "collection `#{}`", c),
395            Self::Capability(c) => write!(f, "capability `#{}`", c),
396        }
397    }
398}
399
400impl FidlIntoNative<OfferTarget> for fdecl::Ref {
401    fn fidl_into_native(self) -> OfferTarget {
402        match self {
403            fdecl::Ref::Child(c) => OfferTarget::Child(c.fidl_into_native()),
404            // cm_fidl_validator should have already validated this
405            fdecl::Ref::Collection(c) => OfferTarget::Collection(c.name.parse().unwrap()),
406            fdecl::Ref::Capability(c) => OfferTarget::Capability(c.name.parse().unwrap()),
407            _ => panic!("invalid OfferTarget variant"),
408        }
409    }
410}
411
412impl NativeIntoFidl<fdecl::Ref> for OfferTarget {
413    fn native_into_fidl(self) -> fdecl::Ref {
414        match self {
415            OfferTarget::Child(c) => fdecl::Ref::Child(c.native_into_fidl()),
416            OfferTarget::Collection(collection_name) => {
417                fdecl::Ref::Collection(fdecl::CollectionRef {
418                    name: collection_name.native_into_fidl(),
419                })
420            }
421            OfferTarget::Capability(capability_name) => {
422                fdecl::Ref::Capability(fdecl::CapabilityRef {
423                    name: capability_name.native_into_fidl(),
424                })
425            }
426        }
427    }
428}