mecha10_cli/services/component_catalog.rs
1#![allow(dead_code)]
2
3//! Component catalog service for managing available components
4//!
5//! This service provides a centralized interface for querying and managing
6//! the catalog of available components (drivers, packages, behaviors, stacks)
7//! that can be added to a Mecha10 project.
8
9use crate::component_catalog::{Component, ComponentCatalog, ComponentType};
10use anyhow::Result;
11
12/// Component catalog service for managing available components
13///
14/// # Examples
15///
16/// ```rust,ignore
17/// use mecha10_cli::services::ComponentCatalogService;
18///
19/// # fn example() -> anyhow::Result<()> {
20/// let service = ComponentCatalogService::new();
21///
22/// // Get all drivers
23/// let drivers = service.get_drivers();
24/// for driver in drivers {
25/// println!("Driver: {} - {}", driver.name, driver.description);
26/// }
27///
28/// // Search for camera components
29/// let cameras = service.search("camera");
30///
31/// // Get a specific component
32/// if let Some(component) = service.get("realsense-camera") {
33/// println!("Found: {}", component.name);
34/// }
35/// # Ok(())
36/// # }
37/// ```
38pub struct ComponentCatalogService {
39 catalog: ComponentCatalog,
40}
41
42impl ComponentCatalogService {
43 /// Create a new component catalog service
44 ///
45 /// Initializes the catalog with all built-in components.
46 pub fn new() -> Self {
47 Self {
48 catalog: ComponentCatalog::new(),
49 }
50 }
51
52 /// Get all available components
53 ///
54 /// Returns a vector of all components in the catalog.
55 pub fn get_all(&self) -> Vec<&Component> {
56 self.catalog.get_all()
57 }
58
59 /// Get all driver components
60 ///
61 /// Returns only components of type Driver.
62 pub fn get_drivers(&self) -> Vec<&Component> {
63 self.catalog.get_by_type(ComponentType::Driver)
64 }
65
66 /// Get all package components
67 ///
68 /// Returns only components of type Package.
69 pub fn get_packages(&self) -> Vec<&Component> {
70 self.catalog.get_by_type(ComponentType::Package)
71 }
72
73 /// Get all behavior components
74 ///
75 /// Returns only components of type Behavior.
76 pub fn get_behaviors(&self) -> Vec<&Component> {
77 self.catalog.get_by_type(ComponentType::Behavior)
78 }
79
80 /// Get all stack components
81 ///
82 /// Returns only components of type Stack (pre-configured sets).
83 pub fn get_stacks(&self) -> Vec<&Component> {
84 self.catalog.get_by_type(ComponentType::Stack)
85 }
86
87 /// Get components by type
88 ///
89 /// # Arguments
90 ///
91 /// * `component_type` - Type of components to retrieve
92 pub fn get_by_type(&self, component_type: ComponentType) -> Vec<&Component> {
93 self.catalog.get_by_type(component_type)
94 }
95
96 /// Get a specific component by ID
97 ///
98 /// # Arguments
99 ///
100 /// * `id` - Component identifier (e.g., "realsense-camera", "rplidar")
101 ///
102 /// # Returns
103 ///
104 /// Some(&Component) if found, None otherwise
105 pub fn get(&self, id: &str) -> Option<&Component> {
106 self.catalog.get(id)
107 }
108
109 /// Search components by query string
110 ///
111 /// Searches component names, descriptions, and tags.
112 ///
113 /// # Arguments
114 ///
115 /// * `query` - Search query (case-insensitive)
116 ///
117 /// # Returns
118 ///
119 /// Vector of components matching the query
120 pub fn search(&self, query: &str) -> Vec<&Component> {
121 self.catalog.search(query)
122 }
123
124 /// List components by category
125 ///
126 /// # Arguments
127 ///
128 /// * `category` - Category name (e.g., "vision", "motion", "sensors")
129 ///
130 /// # Returns
131 ///
132 /// Vector of components in the specified category
133 pub fn get_by_category(&self, category: &str) -> Vec<&Component> {
134 self.catalog
135 .get_all()
136 .into_iter()
137 .filter(|c| c.category == category)
138 .collect()
139 }
140
141 /// List all available categories
142 ///
143 /// # Returns
144 ///
145 /// Sorted vector of unique category names
146 pub fn list_categories(&self) -> Vec<String> {
147 let mut categories: Vec<String> = self.catalog.get_all().iter().map(|c| c.category.clone()).collect();
148
149 categories.sort();
150 categories.dedup();
151 categories
152 }
153
154 /// List all available tags
155 ///
156 /// # Returns
157 ///
158 /// Sorted vector of unique tags
159 pub fn list_tags(&self) -> Vec<String> {
160 let mut tags: Vec<String> = self
161 .catalog
162 .get_all()
163 .iter()
164 .flat_map(|c| c.tags.iter().cloned())
165 .collect();
166
167 tags.sort();
168 tags.dedup();
169 tags
170 }
171
172 /// Get components with a specific tag
173 ///
174 /// # Arguments
175 ///
176 /// * `tag` - Tag to filter by (e.g., "camera", "lidar", "imu")
177 pub fn get_by_tag(&self, tag: &str) -> Vec<&Component> {
178 self.catalog
179 .get_all()
180 .into_iter()
181 .filter(|c| c.tags.iter().any(|t| t == tag))
182 .collect()
183 }
184
185 /// Get component count by type
186 ///
187 /// # Returns
188 ///
189 /// Tuple of (drivers, packages, behaviors, stacks)
190 pub fn get_counts(&self) -> (usize, usize, usize, usize) {
191 let drivers = self.get_drivers().len();
192 let packages = self.get_packages().len();
193 let behaviors = self.get_behaviors().len();
194 let stacks = self.get_stacks().len();
195
196 (drivers, packages, behaviors, stacks)
197 }
198
199 /// Check if a component exists
200 ///
201 /// # Arguments
202 ///
203 /// * `id` - Component identifier
204 pub fn exists(&self, id: &str) -> bool {
205 self.catalog.get(id).is_some()
206 }
207
208 /// Get recommended components for a platform
209 ///
210 /// Returns components commonly used with a specific robot platform.
211 ///
212 /// # Arguments
213 ///
214 /// * `platform` - Platform name (e.g., "rover", "arm", "quadruped")
215 pub fn get_recommended_for_platform(&self, platform: &str) -> Vec<&Component> {
216 // This could be enhanced with platform-specific metadata
217 // For now, return popular components
218 match platform.to_lowercase().as_str() {
219 "rover" => self
220 .search("lidar")
221 .into_iter()
222 .chain(self.search("camera"))
223 .chain(self.search("imu"))
224 .collect(),
225 "arm" => self
226 .search("joint")
227 .into_iter()
228 .chain(self.search("gripper"))
229 .chain(self.search("camera"))
230 .collect(),
231 _ => vec![],
232 }
233 }
234
235 /// Validate component dependencies
236 ///
237 /// Check if all cargo dependencies for a component are valid.
238 ///
239 /// # Arguments
240 ///
241 /// * `component_id` - Component to validate
242 pub fn validate_dependencies(&self, component_id: &str) -> Result<Vec<String>> {
243 let component = self
244 .get(component_id)
245 .ok_or_else(|| anyhow::anyhow!("Component not found: {}", component_id))?;
246
247 let deps: Vec<String> = component
248 .cargo_dependencies
249 .iter()
250 .map(|dep| {
251 if let Some(version) = &dep.version {
252 format!("{} = \"{}\"", dep.name, version)
253 } else if let Some(path) = &dep.path {
254 format!("{} (path: {})", dep.name, path)
255 } else {
256 dep.name.clone()
257 }
258 })
259 .collect();
260
261 Ok(deps)
262 }
263}
264
265impl Default for ComponentCatalogService {
266 fn default() -> Self {
267 Self::new()
268 }
269}