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