pdf_ast/plugins/
registry.rs1use super::*;
2use crate::ast::NodeType;
3use std::collections::HashMap;
4use std::sync::{Arc, RwLock};
5
6pub struct PluginRegistry {
8 plugins: Arc<RwLock<HashMap<String, Arc<dyn AstPlugin>>>>,
9 plugin_metadata: Arc<RwLock<HashMap<String, PluginMetadata>>>,
10 type_mappings: Arc<RwLock<HashMap<NodeType, Vec<String>>>>,
11}
12
13impl PluginRegistry {
14 pub fn new() -> Self {
15 Self {
16 plugins: Arc::new(RwLock::new(HashMap::new())),
17 plugin_metadata: Arc::new(RwLock::new(HashMap::new())),
18 type_mappings: Arc::new(RwLock::new(HashMap::new())),
19 }
20 }
21
22 pub fn register(&self, plugin: Arc<dyn AstPlugin>) -> PluginResult {
24 let metadata = plugin.metadata().clone();
25 let name = metadata.name.clone();
26
27 {
29 let plugins = self.plugins.read().unwrap();
30 if plugins.contains_key(&name) {
31 return PluginResult::Error(format!("Plugin '{}' already registered", name));
32 }
33 }
34
35 {
37 let mut plugins = self.plugins.write().unwrap();
38 plugins.insert(name.clone(), plugin.clone());
39 }
40
41 {
43 let mut plugin_metadata = self.plugin_metadata.write().unwrap();
44 plugin_metadata.insert(name.clone(), metadata.clone());
45 }
46
47 {
49 let mut type_mappings = self.type_mappings.write().unwrap();
50 for node_type_str in &metadata.supported_node_types {
51 if let Ok(node_type) = self.parse_node_type(node_type_str) {
52 type_mappings
53 .entry(node_type)
54 .or_default()
55 .push(name.clone());
56 }
57 }
58 }
59
60 PluginResult::Success
61 }
62
63 pub fn unregister(&self, name: &str) -> PluginResult {
65 let plugin_existed = {
67 let mut plugins = self.plugins.write().unwrap();
68 plugins.remove(name).is_some()
69 };
70
71 if !plugin_existed {
72 return PluginResult::Error(format!("Plugin '{}' not found", name));
73 }
74
75 let metadata = {
77 let mut plugin_metadata = self.plugin_metadata.write().unwrap();
78 plugin_metadata.remove(name)
79 };
80
81 if let Some(metadata) = metadata {
83 let mut type_mappings = self.type_mappings.write().unwrap();
84 for node_type_str in &metadata.supported_node_types {
85 if let Ok(node_type) = self.parse_node_type(node_type_str) {
86 if let Some(plugin_names) = type_mappings.get_mut(&node_type) {
87 plugin_names.retain(|n| n != name);
88 if plugin_names.is_empty() {
89 type_mappings.remove(&node_type);
90 }
91 }
92 }
93 }
94 }
95
96 PluginResult::Success
97 }
98
99 pub fn get_plugin(&self, name: &str) -> Option<Arc<dyn AstPlugin>> {
101 let plugins = self.plugins.read().unwrap();
102 plugins.get(name).cloned()
103 }
104
105 pub fn list_plugins(&self) -> Vec<String> {
107 let plugins = self.plugins.read().unwrap();
108 plugins.keys().cloned().collect()
109 }
110
111 pub fn get_plugins_for_type(&self, node_type: &NodeType) -> Vec<Arc<dyn AstPlugin>> {
113 let type_mappings = self.type_mappings.read().unwrap();
114 let plugins = self.plugins.read().unwrap();
115
116 if let Some(plugin_names) = type_mappings.get(node_type) {
117 plugin_names
118 .iter()
119 .filter_map(|name| plugins.get(name).cloned())
120 .collect()
121 } else {
122 Vec::new()
123 }
124 }
125
126 pub fn get_metadata(&self, name: &str) -> Option<PluginMetadata> {
128 let plugin_metadata = self.plugin_metadata.read().unwrap();
129 plugin_metadata.get(name).cloned()
130 }
131
132 pub fn list_metadata(&self) -> Vec<PluginMetadata> {
134 let plugin_metadata = self.plugin_metadata.read().unwrap();
135 plugin_metadata.values().cloned().collect()
136 }
137
138 pub fn find_by_tag(&self, tag: &str) -> Vec<String> {
140 let plugin_metadata = self.plugin_metadata.read().unwrap();
141 plugin_metadata
142 .iter()
143 .filter(|(_, metadata)| metadata.tags.contains(&tag.to_string()))
144 .map(|(name, _)| name.clone())
145 .collect()
146 }
147
148 pub fn find_by_author(&self, author: &str) -> Vec<String> {
150 let plugin_metadata = self.plugin_metadata.read().unwrap();
151 plugin_metadata
152 .iter()
153 .filter(|(_, metadata)| metadata.author == author)
154 .map(|(name, _)| name.clone())
155 .collect()
156 }
157
158 pub fn check_dependencies(&self, name: &str) -> PluginResult {
160 let plugin_metadata = self.plugin_metadata.read().unwrap();
161
162 if let Some(metadata) = plugin_metadata.get(name) {
163 for dependency in &metadata.dependencies {
164 if !plugin_metadata.contains_key(dependency) {
165 return PluginResult::Error(format!(
166 "Plugin '{}' depends on '{}' which is not registered",
167 name, dependency
168 ));
169 }
170 }
171 PluginResult::Success
172 } else {
173 PluginResult::Error(format!("Plugin '{}' not found", name))
174 }
175 }
176
177 pub fn get_dependency_order(&self, plugin_names: &[String]) -> Result<Vec<String>, String> {
179 let plugin_metadata = self.plugin_metadata.read().unwrap();
180 let mut result = Vec::new();
181 let mut visited = std::collections::HashSet::new();
182 let mut visiting = std::collections::HashSet::new();
183
184 fn visit(
185 name: &str,
186 plugin_metadata: &HashMap<String, PluginMetadata>,
187 result: &mut Vec<String>,
188 visited: &mut std::collections::HashSet<String>,
189 visiting: &mut std::collections::HashSet<String>,
190 ) -> Result<(), String> {
191 if visiting.contains(name) {
192 return Err(format!("Circular dependency detected involving '{}'", name));
193 }
194
195 if visited.contains(name) {
196 return Ok(());
197 }
198
199 visiting.insert(name.to_string());
200
201 if let Some(metadata) = plugin_metadata.get(name) {
202 for dependency in &metadata.dependencies {
203 visit(dependency, plugin_metadata, result, visited, visiting)?;
204 }
205 }
206
207 visiting.remove(name);
208 visited.insert(name.to_string());
209 result.push(name.to_string());
210
211 Ok(())
212 }
213
214 for name in plugin_names {
215 visit(
216 name,
217 &plugin_metadata,
218 &mut result,
219 &mut visited,
220 &mut visiting,
221 )?;
222 }
223
224 Ok(result)
225 }
226
227 pub fn clear(&self) {
229 let mut plugins = self.plugins.write().unwrap();
230 plugins.clear();
231
232 let mut plugin_metadata = self.plugin_metadata.write().unwrap();
233 plugin_metadata.clear();
234
235 let mut type_mappings = self.type_mappings.write().unwrap();
236 type_mappings.clear();
237 }
238
239 pub fn count(&self) -> usize {
241 let plugins = self.plugins.read().unwrap();
242 plugins.len()
243 }
244
245 fn parse_node_type(&self, type_str: &str) -> Result<NodeType, String> {
247 match type_str {
248 "Catalog" => Ok(NodeType::Catalog),
249 "Pages" => Ok(NodeType::Pages),
250 "Page" => Ok(NodeType::Page),
251 "ContentStream" => Ok(NodeType::ContentStream),
252 "Font" => Ok(NodeType::Font),
253 "Type1Font" => Ok(NodeType::Type1Font),
254 "TrueTypeFont" => Ok(NodeType::TrueTypeFont),
255 "Type3Font" => Ok(NodeType::Type3Font),
256 "Image" => Ok(NodeType::Image),
257 "Annotation" => Ok(NodeType::Annotation),
258 "Outline" => Ok(NodeType::Outline),
259 "Action" => Ok(NodeType::Action),
260 "Encryption" => Ok(NodeType::Encryption),
261 "Metadata" => Ok(NodeType::Metadata),
262 "Structure" => Ok(NodeType::Structure),
263 "Form" => Ok(NodeType::Form),
264 "JavaScript" => Ok(NodeType::JavaScript),
265 "Multimedia" => Ok(NodeType::Multimedia),
266 "ColorSpace" => Ok(NodeType::ColorSpace),
267 "Pattern" => Ok(NodeType::Pattern),
268 "Shading" => Ok(NodeType::Shading),
269 "XObject" => Ok(NodeType::XObject),
270 "EmbeddedFile" => Ok(NodeType::EmbeddedFile),
271 "Other" => Ok(NodeType::Other),
272 _ => Err(format!("Unknown node type: {}", type_str)),
273 }
274 }
275}
276
277impl Default for PluginRegistry {
278 fn default() -> Self {
279 Self::new()
280 }
281}
282
283impl Clone for PluginRegistry {
284 fn clone(&self) -> Self {
285 Self {
286 plugins: Arc::clone(&self.plugins),
287 plugin_metadata: Arc::clone(&self.plugin_metadata),
288 type_mappings: Arc::clone(&self.type_mappings),
289 }
290 }
291}