Skip to main content

fdf_metadata/
lib.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
5mod serde;
6
7use fdf_component::ServiceOffer;
8use fidl_fuchsia_driver_framework as fdf;
9use fidl_next::{Responder, ServerEnd};
10use fidl_next_fuchsia_driver_metadata as fmetadata;
11use fidl_next_fuchsia_hardware_platform_device as fdevice_next;
12use fuchsia_async as fasync;
13use fuchsia_component::server::{ServiceFs, ServiceObjTrait};
14use std::sync::Arc;
15
16pub use serde::*;
17
18pub struct MetadataServer {
19    data: Option<Arc<Vec<u8>>>,
20    name: String,
21}
22
23impl MetadataServer {
24    pub fn new(name: impl Into<String>) -> Self {
25        Self { data: None, name: name.into() }
26    }
27
28    pub fn with_metadata<T: fidl::Persistable>(self, metadata: &T) -> Result<Self, zx::Status> {
29        let data = fidl::persist(metadata).map_err(|_| zx::Status::INTERNAL)?;
30        Ok(Self { data: Some(Arc::new(data)), name: self.name })
31    }
32
33    pub async fn forward_from_pdev(
34        self,
35        pdev: &fidl_fuchsia_hardware_platform_device::DeviceProxy,
36    ) -> Result<Self, zx::Status> {
37        let data = pdev
38            .get_metadata(&self.name)
39            .await
40            .map_err(|_| zx::Status::INTERNAL)?
41            .map_err(zx::Status::err_from_raw)?;
42        Ok(Self { data: Some(Arc::new(data)), name: self.name })
43    }
44
45    pub async fn forward_from_pdev_next(
46        self,
47        pdev: &fidl_next::Client<fdevice_next::Device>,
48    ) -> Result<Self, zx::Status> {
49        let data = pdev
50            .get_metadata(&self.name)
51            .await
52            .map_err(|_| zx::Status::INTERNAL)?
53            .map_err(|e| e.err().unwrap_or(zx::Status::INTERNAL))?
54            .metadata;
55        Ok(Self { data: Some(Arc::new(data)), name: self.name })
56    }
57
58    pub fn create_handler(&self, scope: fasync::ScopeHandle) -> Option<MetadataHandler> {
59        let data = self.data.clone()?;
60        Some(MetadataHandler { data, scope })
61    }
62
63    pub fn create_service_offer(&self) -> Option<ServiceOffer<fmetadata::Service>> {
64        Some(ServiceOffer::<fmetadata::Service>::new_next())
65    }
66
67    pub fn serve<O>(
68        &self,
69        fs: &mut ServiceFs<O>,
70        scope: fasync::ScopeHandle,
71        instance_name: impl Into<String>,
72    ) -> Option<fdf::Offer>
73    where
74        O: ServiceObjTrait,
75    {
76        let data = self.data.clone()?;
77        let handler = MetadataHandler { data, scope };
78
79        let offer = ServiceOffer::<fmetadata::Service>::new_with_name(self.name.clone())
80            .add_default_named_next(fs, instance_name, handler)
81            .build_zircon_offer_next();
82
83        Some(offer)
84    }
85}
86
87pub struct MetadataHandler {
88    data: Arc<Vec<u8>>,
89    scope: fasync::ScopeHandle,
90}
91
92impl fmetadata::ServiceHandler for MetadataHandler {
93    fn metadata(&self, server_end: ServerEnd<fmetadata::Metadata>) {
94        let data = self.data.clone();
95        self.scope.spawn_local(async move {
96            let dispatcher = fidl_next::ServerDispatcher::new(server_end);
97            let _ = dispatcher.run_local(MetadataServerImpl { data }).await;
98        });
99    }
100}
101
102struct MetadataServerImpl {
103    data: Arc<Vec<u8>>,
104}
105
106impl fmetadata::MetadataLocalServerHandler for MetadataServerImpl {
107    async fn get_persisted_metadata(
108        &mut self,
109        responder: Responder<fmetadata::metadata::GetPersistedMetadata>,
110    ) {
111        let _ = responder.respond(self.data.as_slice()).await;
112    }
113}