fdf_component/node/offers.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
// Copyright 2024 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::marker::PhantomData;
use fidl::endpoints::{ServiceMarker, ServiceRequest};
use fidl_fuchsia_component_decl::{NameMapping, OfferService};
use fidl_fuchsia_driver_framework::Offer;
use fuchsia_component::server::{FidlServiceMember, ServiceFs, ServiceObjTrait};
use fuchsia_component::DEFAULT_SERVICE_INSTANCE;
/// A builder for creating [`Offer`]-compatible values for [`crate::NodeBuilder::add_offer`] that
/// service a zircon fidl service.
///
/// The methods on this that start with `add_` are helpers that will both register a service handler
/// with a [`ServiceFs`] and register the instance name in the structure. If you're handling adding
/// your service handlers to the outgoing directory yourself, you can just use the non-`add_`
/// methods to register them.
///
/// If no calls to add any instances are made, then when this is transformed into a service offer
/// it will be as if a single default instance with the default name was added.
pub struct ZirconServiceOffer<S> {
service_name: String,
instances: Vec<NameMapping>,
_p: PhantomData<S>,
}
impl<S> ZirconServiceOffer<S> {
/// Builds an offer for a zircon transport service based on the [`ServiceMarker`] for `S`.
///
/// If the compiler can't deduce the type of `S` (which may be the case if you're not using the
/// `add_` methods to add to a [`ServiceFs`] at the same time), you can use [`Self::new_marker`]
/// to make it explicit.
pub fn new() -> Self
where
S: ServiceMarker,
{
let service_name = S::SERVICE_NAME.to_owned();
let instances = vec![];
Self { service_name, instances, _p: PhantomData }
}
/// Builds an offer for a zircon transport service based on the given [`ServiceMarker`].
///
/// This is mostly useful if the compiler can't derive the type of `S` on its own.
pub fn new_marker(_marker: S) -> Self
where
S: ServiceMarker,
{
let service_name = S::SERVICE_NAME.to_owned();
let instances = vec![];
Self { service_name, instances, _p: PhantomData }
}
/// Adds the given service instance to this offer and to the [`ServiceFs`] passed in, using the
/// generator function `f`. The type of the service will be derived from the result of the
/// generator function and it will be added with the name `name` which will be mapped to the
/// default instance name to child components ([`DEFAULT_SERVICE_INSTANCE`]).
pub fn add_default_named<O: ServiceObjTrait, F, SR>(
self,
fs: &mut ServiceFs<O>,
name: impl Into<String>,
f: F,
) -> Self
where
F: Fn(SR) -> O::Output,
F: Clone,
SR: ServiceRequest<Service = S>,
FidlServiceMember<F, SR, O::Output>: Into<O>,
{
let name = name.into();
fs.dir("svc").add_fidl_service_instance(name.clone(), f);
self.named_default_instance(name)
}
/// Adds the given service instance to this offer and to the [`ServiceFs`] passed in, using the
/// generator function `f`. The type of the service will be derived from the result of the
/// generator function and it will be added with the name `name`.
pub fn add_named<O: ServiceObjTrait, F, SR>(
self,
fs: &mut ServiceFs<O>,
name: impl Into<String>,
f: F,
) -> Self
where
F: Fn(SR) -> O::Output,
F: Clone,
SR: ServiceRequest<Service = S>,
FidlServiceMember<F, SR, O::Output>: Into<O>,
{
let name = name.into();
fs.dir("svc").add_fidl_service_instance(name.clone(), f);
self.named_instance(name)
}
/// Adds the named instance as the `default` instance of this service offer (as specified
/// by [`DEFAULT_SERVICE_INSTANCE`]). If you are only offering a single instance that is
/// already called `default`, you do not need to call this.
pub fn named_default_instance(mut self, name: impl Into<String>) -> Self {
self.instances.push(NameMapping {
source_name: name.into(),
target_name: DEFAULT_SERVICE_INSTANCE.to_owned(),
});
self
}
/// Adds the named instance to the offer without mapping it to the default instance name.
/// You can use this to add additional instances offered in your outgoing directory.
pub fn named_instance(mut self, name: impl Into<String>) -> Self {
let source_name = name.into();
let target_name = source_name.clone();
self.instances.push(NameMapping { source_name, target_name });
self
}
/// Finalize the construction of the [`Offer`] object for use with
/// [`super::NodeBuilder::add_offer`].
pub fn build(self) -> Offer {
// if no instances were added, assume there's a single default instance
let mut instances = self.instances;
if instances.is_empty() {
instances.push(NameMapping {
source_name: DEFAULT_SERVICE_INSTANCE.to_owned(),
target_name: DEFAULT_SERVICE_INSTANCE.to_owned(),
});
}
let service = OfferService {
source_name: Some(self.service_name.clone()),
target_name: Some(self.service_name),
renamed_instances: Some(instances),
..Default::default()
};
Offer::ZirconTransport(fidl_fuchsia_component_decl::Offer::Service(service))
}
}