Skip to main content

driver_manager_composite/
spec.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 crate::parent_set_collector::ParentSetCollector;
6use driver_manager_node::{Node, NodeManager, NodeProperty, NodePropertyValue};
7use flyweights::FlyStr;
8use futures::channel::oneshot;
9use std::rc::{Rc, Weak};
10use {fidl_fuchsia_driver_development as fdd, fidl_fuchsia_driver_framework as fdf};
11
12#[derive(Copy, Clone)]
13pub enum Condition {
14    Unknown = 0,
15    Accept = 1,
16    Reject = 2,
17}
18
19impl std::convert::From<fdf::Condition> for Condition {
20    fn from(source: fdf::Condition) -> Self {
21        match source {
22            fdf::Condition::Unknown => Self::Unknown,
23            fdf::Condition::Accept => Self::Accept,
24            fdf::Condition::Reject => Self::Reject,
25        }
26    }
27}
28
29impl std::convert::From<Condition> for fdf::Condition {
30    fn from(source: Condition) -> fdf::Condition {
31        match source {
32            Condition::Unknown => fdf::Condition::Unknown,
33            Condition::Accept => fdf::Condition::Accept,
34            Condition::Reject => fdf::Condition::Reject,
35        }
36    }
37}
38
39#[derive(Clone)]
40pub struct BindRule {
41    pub key: FlyStr,
42    pub condition: Condition,
43    pub values: Vec<NodePropertyValue>,
44}
45
46impl std::convert::From<fdf::BindRule2> for BindRule {
47    fn from(source: fdf::BindRule2) -> Self {
48        Self {
49            key: FlyStr::new(source.key),
50            condition: source.condition.into(),
51            values: source.values.into_iter().map(|v| v.into()).collect(),
52        }
53    }
54}
55
56impl std::convert::From<BindRule> for fdf::BindRule2 {
57    fn from(source: BindRule) -> fdf::BindRule2 {
58        fdf::BindRule2 {
59            key: source.key.to_string(),
60            condition: source.condition.into(),
61            values: source.values.into_iter().map(|v| v.into()).collect(),
62        }
63    }
64}
65
66#[derive(Clone)]
67pub struct ParentSpec {
68    pub bind_rules: Vec<BindRule>,
69    pub properties: Vec<NodeProperty>,
70}
71
72impl std::convert::From<fdf::ParentSpec2> for ParentSpec {
73    fn from(source: fdf::ParentSpec2) -> Self {
74        Self {
75            bind_rules: source.bind_rules.into_iter().map(|b| b.into()).collect(),
76            properties: source.properties.into_iter().map(|p| p.into()).collect(),
77        }
78    }
79}
80
81impl std::convert::From<ParentSpec> for fdf::ParentSpec2 {
82    fn from(source: ParentSpec) -> fdf::ParentSpec2 {
83        fdf::ParentSpec2 {
84            bind_rules: source.bind_rules.into_iter().map(|b| b.into()).collect(),
85            properties: source.properties.into_iter().map(|p| p.into()).collect(),
86        }
87    }
88}
89
90#[derive(Clone)]
91pub struct NodeSpec {
92    pub name: String,
93    pub parents: Vec<ParentSpec>,
94    pub driver_host: Option<String>,
95}
96
97impl std::convert::From<fdf::CompositeNodeSpec> for NodeSpec {
98    fn from(source: fdf::CompositeNodeSpec) -> Self {
99        Self {
100            name: source.name.unwrap(),
101            parents: source.parents2.unwrap().into_iter().map(|p| p.into()).collect(),
102            driver_host: source.driver_host,
103        }
104    }
105}
106
107#[derive(Clone)]
108pub struct DriverInfo {
109    pub url: String,
110    pub name: Option<String>,
111    pub colocate: bool,
112    pub package_type: fdf::DriverPackageType,
113    pub is_fallback: bool,
114    pub device_categories: Vec<fdf::DeviceCategory>,
115    pub bind_rules_bytecode: Vec<u8>,
116    pub driver_framework_version: u8,
117    pub is_disabled: bool,
118}
119
120impl std::convert::From<fdf::DriverInfo> for DriverInfo {
121    fn from(source: fdf::DriverInfo) -> Self {
122        Self {
123            url: source.url.unwrap(),
124            name: source.name,
125            colocate: source.colocate.unwrap(),
126            package_type: source.package_type.unwrap(),
127            is_fallback: source.is_fallback.unwrap(),
128            device_categories: source.device_categories.unwrap(),
129            bind_rules_bytecode: source.bind_rules_bytecode.unwrap_or_default(),
130            driver_framework_version: source.driver_framework_version.unwrap(),
131            is_disabled: source.is_disabled.unwrap(),
132        }
133    }
134}
135
136impl std::convert::From<DriverInfo> for fdf::DriverInfo {
137    fn from(source: DriverInfo) -> fdf::DriverInfo {
138        fdf::DriverInfo {
139            url: Some(source.url),
140            name: source.name,
141            colocate: Some(source.colocate),
142            package_type: Some(source.package_type),
143            is_fallback: Some(source.is_fallback),
144            device_categories: Some(source.device_categories),
145            bind_rules_bytecode: Some(source.bind_rules_bytecode),
146            driver_framework_version: Some(source.driver_framework_version),
147            is_disabled: Some(source.is_disabled),
148            ..Default::default()
149        }
150    }
151}
152
153#[derive(Clone)]
154pub struct CompositeDriverInfo {
155    pub composite_name: String,
156    pub driver_info: DriverInfo,
157}
158
159impl std::convert::From<fdf::CompositeDriverInfo> for CompositeDriverInfo {
160    fn from(source: fdf::CompositeDriverInfo) -> Self {
161        Self {
162            composite_name: source.composite_name.unwrap(),
163            driver_info: source.driver_info.unwrap().into(),
164        }
165    }
166}
167
168#[derive(Clone)]
169pub struct CompositeDriverMatch {
170    pub composite_driver: CompositeDriverInfo,
171    pub parent_names: Vec<String>,
172    pub primary_parent_index: u32,
173}
174
175impl std::convert::From<fdf::CompositeDriverMatch> for CompositeDriverMatch {
176    fn from(source: fdf::CompositeDriverMatch) -> Self {
177        Self {
178            composite_driver: source.composite_driver.unwrap().into(),
179            parent_names: source.parent_names.unwrap(),
180            primary_parent_index: source.primary_parent_index.unwrap_or(0),
181        }
182    }
183}
184
185#[derive(Clone)]
186pub struct CompositeInfo {
187    pub spec: NodeSpec,
188    pub matched_driver: CompositeDriverMatch,
189}
190
191impl std::convert::From<fdf::CompositeInfo> for CompositeInfo {
192    fn from(source: fdf::CompositeInfo) -> Self {
193        Self {
194            spec: source.spec.unwrap().into(),
195            matched_driver: source.matched_driver.unwrap().into(),
196        }
197    }
198}
199
200pub struct CompositeNodeSpec {
201    #[allow(unused)]
202    name: String,
203    parent_specs: Vec<ParentSpec>,
204    parent_nodes: Vec<Option<Weak<Node>>>,
205    parent_set_collector: Option<ParentSetCollector>,
206    driver_url: String,
207    node_manager: Box<dyn NodeManager>,
208    composite_info: Option<CompositeInfo>,
209    driver_host_name_for_colocation: String,
210}
211
212impl CompositeNodeSpec {
213    pub fn new(
214        name: String,
215        parent_specs: Vec<fdf::ParentSpec2>,
216        node_manager: Box<dyn NodeManager>,
217        driver_host_name_for_colocation: String,
218    ) -> Self {
219        let parent_nodes = vec![None; parent_specs.len()];
220        Self {
221            name,
222            parent_specs: parent_specs.into_iter().map(|p| p.into()).collect(),
223            parent_nodes,
224            parent_set_collector: None,
225            driver_url: String::new(),
226            node_manager,
227            composite_info: None,
228            driver_host_name_for_colocation,
229        }
230    }
231
232    fn bind_parent_impl(
233        &mut self,
234        composite_parent: fdf::CompositeParent,
235        node_ptr: Weak<Node>,
236    ) -> Result<Option<Weak<Node>>, zx::Status> {
237        if self.composite_info.is_none() {
238            self.composite_info = composite_parent.composite.map(|c| c.into());
239        }
240
241        let composite_info = self.composite_info.as_ref().unwrap();
242        let spec = &composite_info.spec;
243        let matched_driver = &composite_info.matched_driver;
244        let spec_name = &spec.name;
245        let composite_driver = &matched_driver.composite_driver;
246        let driver_info = &composite_driver.driver_info;
247        let parent_names = &matched_driver.parent_names;
248        let primary_index = matched_driver.primary_parent_index;
249        let url = &driver_info.url;
250
251        if self.parent_set_collector.is_none() {
252            self.parent_set_collector = Some(ParentSetCollector::new(
253                spec_name.clone(),
254                parent_names.clone(),
255                primary_index,
256                self.driver_host_name_for_colocation.clone(),
257            ));
258            self.driver_url = url.clone();
259        }
260
261        let collector = self.parent_set_collector.as_mut().unwrap();
262        let index = composite_parent.index.unwrap();
263        let properties = self.parent_specs[index as usize].properties.clone();
264        collector.add_node(index, properties, node_ptr)?;
265
266        match collector.try_to_assemble(self.node_manager.clone_box()) {
267            Ok(node) => Ok(Some(Rc::downgrade(&node))),
268            Err(zx::Status::SHOULD_WAIT) => Ok(None),
269            Err(e) => Err(e),
270        }
271    }
272
273    pub fn bind_parent(
274        &mut self,
275        composite_parent: fdf::CompositeParent,
276        node_ptr: Weak<Node>,
277    ) -> Result<Option<Weak<Node>>, zx::Status> {
278        let node_index = composite_parent.index.unwrap() as usize;
279        if node_index >= self.parent_nodes.len() {
280            return Err(zx::Status::OUT_OF_RANGE);
281        }
282
283        if let Some(current_at_index) = &self.parent_nodes[node_index]
284            && current_at_index.upgrade().is_some()
285        {
286            return Err(zx::Status::ALREADY_BOUND);
287        }
288
289        let result = self.bind_parent_impl(composite_parent, node_ptr.clone());
290        if result.is_ok() {
291            self.parent_nodes[node_index] = Some(node_ptr);
292        }
293        result
294    }
295
296    pub fn get_composite_info(&self) -> fdd::CompositeNodeInfo {
297        let mut info = fdd::CompositeNodeInfo::default();
298        if self.parent_set_collector.is_none() {
299            info.parent_topological_paths = Some(vec![None; self.parent_nodes.len()]);
300            return info;
301        }
302
303        if let Some(composite_info) = &self.composite_info {
304            let spec = Some(fdf::CompositeNodeSpec {
305                name: Some(composite_info.spec.name.clone()),
306                parents2: Some(
307                    composite_info.spec.parents.clone().into_iter().map(|p| p.into()).collect(),
308                ),
309                ..Default::default()
310            });
311
312            let md = &composite_info.matched_driver;
313            let matched_driver = Some(fdf::CompositeDriverMatch {
314                composite_driver: Some({
315                    fdf::CompositeDriverInfo {
316                        composite_name: Some(md.composite_driver.composite_name.clone()),
317                        driver_info: Some(md.composite_driver.driver_info.clone().into()),
318                        ..Default::default()
319                    }
320                }),
321                parent_names: Some(md.parent_names.clone()),
322                primary_parent_index: Some(md.primary_parent_index),
323                ..Default::default()
324            });
325
326            info.composite = Some(fdd::CompositeInfo::Composite(fdf::CompositeInfo {
327                spec,
328                matched_driver,
329                ..Default::default()
330            }));
331        }
332
333        let collector = self.parent_set_collector.as_ref().unwrap();
334        info.parent_topological_paths = Some(collector.get_parent_topological_paths());
335
336        if let Some(node_weak) = collector.completed_composite_node()
337            && let Some(node) = node_weak.upgrade()
338        {
339            info.topological_path = Some(node.make_topological_path(false));
340        }
341        info
342    }
343
344    pub fn remove(&mut self, callback: oneshot::Sender<Result<(), zx::Status>>) {
345        self.parent_nodes = vec![None; self.parent_specs.len()];
346        if self.parent_set_collector.is_none() {
347            let _ = callback.send(Ok(()));
348            return;
349        }
350
351        let collector = self.parent_set_collector.as_mut().unwrap();
352        collector.release_nodes();
353
354        if let Some(node_weak) = collector.completed_composite_node()
355            && let Some(node) = node_weak.upgrade()
356        {
357            node.remove_composite_node_for_rebind(callback);
358            self.parent_set_collector = None;
359            self.driver_url.clear();
360            self.composite_info = None;
361            return;
362        }
363
364        self.parent_set_collector = None;
365        self.driver_url.clear();
366        self.composite_info = None;
367        let _ = callback.send(Ok(()));
368    }
369}