Skip to main content

ass_editor/extensions/
manager.rs

1//! Extension manager type definitions and shared internals.
2//!
3//! Houses the `ExtensionManager` handle, its internal storage, the inner-access
4//! helpers shared across the manager implementation, and the event-sender alias.
5
6use core::fmt;
7
8#[cfg(feature = "std")]
9use crate::events::DocumentEvent;
10
11use super::command::{ExtensionCommand, ExtensionState};
12use super::extension::{EditorExtension, MessageHandler};
13
14#[cfg(feature = "std")]
15use std::collections::HashMap;
16
17#[cfg(not(feature = "std"))]
18use alloc::collections::BTreeMap as HashMap;
19
20#[cfg(not(feature = "std"))]
21use alloc::{boxed::Box, string::String, vec::Vec};
22
23#[cfg(feature = "multi-thread")]
24use std::sync::Arc;
25
26#[cfg(not(feature = "multi-thread"))]
27use core::cell::RefCell;
28
29/// Extension manager with built-in thread safety
30#[cfg(feature = "multi-thread")]
31use parking_lot::Mutex;
32
33#[cfg(feature = "std")]
34use std::sync::mpsc::Sender;
35
36/// Event sender type for channel communication
37#[cfg(feature = "std")]
38pub type EventSender = Sender<DocumentEvent>;
39
40#[cfg(not(feature = "std"))]
41pub type EventSender = (); // No-op for no_std environments
42
43/// Extension manager for loading and managing extensions
44/// Internal storage for ExtensionManager data
45pub(super) struct ExtensionManagerInner {
46    /// Loaded extensions
47    pub(super) extensions: HashMap<String, Box<dyn EditorExtension>>,
48
49    /// Extension states
50    pub(super) extension_states: HashMap<String, ExtensionState>,
51
52    /// Available commands from all extensions
53    pub(super) commands: HashMap<String, (String, ExtensionCommand)>, // command_id -> (extension_name, command)
54
55    /// Configuration storage
56    pub(super) config: HashMap<String, String>,
57
58    /// Inter-extension data storage
59    pub(super) extension_data: HashMap<String, HashMap<String, String>>,
60
61    /// Event channel for sending events
62    #[cfg(feature = "std")]
63    #[allow(dead_code)]
64    pub(super) event_tx: EventSender,
65
66    /// Message handler for user notifications
67    #[allow(dead_code)]
68    pub(super) message_handler: Box<dyn MessageHandler>,
69}
70
71/// Single unified ExtensionManager that is always thread-safe when multi-thread feature is enabled
72pub struct ExtensionManager {
73    #[cfg(feature = "multi-thread")]
74    pub(super) inner: Arc<Mutex<ExtensionManagerInner>>,
75    #[cfg(not(feature = "multi-thread"))]
76    pub(super) inner: RefCell<ExtensionManagerInner>,
77}
78
79// ExtensionManager is cloneable when multi-thread feature is enabled
80#[cfg(feature = "multi-thread")]
81impl Clone for ExtensionManager {
82    fn clone(&self) -> Self {
83        Self {
84            inner: self.inner.clone(),
85        }
86    }
87}
88
89// Note: ExtensionManager does not implement Clone without multi-thread feature
90// This is intentional - cloning requires Arc<Mutex<T>> which needs multi-thread
91
92impl fmt::Debug for ExtensionManager {
93    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94        #[cfg(feature = "multi-thread")]
95        {
96            let inner = self.inner.lock();
97            f.debug_struct("ExtensionManager")
98                .field("extension_states", &inner.extension_states)
99                .field("commands", &inner.commands.keys().collect::<Vec<_>>())
100                .field("config", &inner.config)
101                .field("extension_data", &inner.extension_data)
102                .field("extensions", &"<HashMap<String, Box<dyn EditorExtension>>>")
103                .finish()
104        }
105        #[cfg(not(feature = "multi-thread"))]
106        {
107            let inner = self.inner.borrow();
108            f.debug_struct("ExtensionManager")
109                .field("extension_states", &inner.extension_states)
110                .field("commands", &inner.commands.keys().collect::<Vec<_>>())
111                .field("config", &inner.config)
112                .field("extension_data", &inner.extension_data)
113                .field("extensions", &"<HashMap<String, Box<dyn EditorExtension>>>")
114                .finish()
115        }
116    }
117}
118
119impl ExtensionManager {
120    /// Helper method for accessing inner data mutably
121    #[cfg(feature = "multi-thread")]
122    pub(super) fn with_inner_mut<F, R>(&self, f: F) -> R
123    where
124        F: FnOnce(&mut ExtensionManagerInner) -> R,
125    {
126        let mut inner = self.inner.lock();
127        f(&mut inner)
128    }
129
130    /// Helper method for accessing inner data immutably
131    #[cfg(feature = "multi-thread")]
132    pub(super) fn with_inner<F, R>(&self, f: F) -> R
133    where
134        F: FnOnce(&ExtensionManagerInner) -> R,
135    {
136        let inner = self.inner.lock();
137        f(&inner)
138    }
139
140    /// Helper method for accessing inner data mutably
141    #[cfg(not(feature = "multi-thread"))]
142    pub(super) fn with_inner_mut<F, R>(&self, f: F) -> R
143    where
144        F: FnOnce(&mut ExtensionManagerInner) -> R,
145    {
146        let mut inner = self.inner.borrow_mut();
147        f(&mut inner)
148    }
149
150    /// Helper method for accessing inner data immutably
151    #[cfg(not(feature = "multi-thread"))]
152    pub(super) fn with_inner<F, R>(&self, f: F) -> R
153    where
154        F: FnOnce(&ExtensionManagerInner) -> R,
155    {
156        let inner = self.inner.borrow();
157        f(&inner)
158    }
159}
160
161impl Default for ExtensionManager {
162    fn default() -> Self {
163        Self::new()
164    }
165}