reovim_kernel/api/service.rs
1//! Service registry for cross-module service discovery.
2//!
3//! Provides two registry types:
4//! - [`ServiceRegistry`]: For unique services (one provider per type)
5//! - [`MultiServiceRegistry`]: For keyed services (multiple providers with typed keys)
6//!
7//! # Architecture
8//!
9//! This module implements the **generic mechanism** for service discovery.
10//! Specific service traits and typed keys are defined in their respective drivers.
11//!
12//! ```text
13//! server/lib/kernel/api/service/ → Generic ServiceRegistry (this module)
14//! server/lib/drivers/vfs/ → VfsScheme enum + VfsProviderRegistry
15//! server/lib/drivers/input/ → ModeProviderKey enum + ModeProviderRegistry
16//! ```
17//!
18//! # Example
19//!
20//! ```ignore
21//! use reovim_kernel::api::v1::{ServiceRegistry, MultiServiceRegistry, ServiceKey};
22//!
23//! // Unique service (one provider per type)
24//! let registry = ServiceRegistry::new();
25//! registry.register::<MyService>(Arc::new(my_service));
26//! let service = registry.get::<MyService>();
27//!
28//! // Keyed service (multiple providers)
29//! let vfs_registry = MultiServiceRegistry::<VfsScheme, dyn VfsDriver>::new();
30//! vfs_registry.register(VfsScheme::File, Arc::new(local_fs));
31//! let driver = vfs_registry.get(&VfsScheme::File);
32//! ```
33
34use std::{
35 any::{Any, TypeId},
36 collections::HashMap,
37 fmt,
38 hash::Hash,
39 sync::Arc,
40};
41
42use reovim_arch::sync::RwLock;
43
44// ============================================================================
45// Service Trait
46// ============================================================================
47
48/// Marker trait for services that can be registered in [`ServiceRegistry`].
49///
50/// Implement this trait for types that should be discoverable via the
51/// service registry. The trait bounds ensure thread-safety.
52pub trait Service: Send + Sync + 'static {}
53
54// ============================================================================
55// ServiceKey Trait (typed key marker)
56// ============================================================================
57
58/// Marker trait for typed service keys.
59///
60/// Each driver defines its own key enum implementing this trait.
61/// This ensures compile-time safety and provides metadata for error messages.
62///
63/// # Safety Contract
64///
65/// **DO NOT** use `service_name()` for:
66/// - Runtime service routing or comparison
67/// - Dynamic dispatch based on string matching
68/// - Escape hatch to bypass typed key lookup
69///
70/// The `service_name()` method exists **ONLY** for human-readable error messages.
71/// All service lookup MUST use the typed key directly via `get(key)`.
72///
73/// # Correct Usage
74///
75/// ```ignore
76/// // GOOD: Direct typed key lookup
77/// let vfs = registry.get(&VfsScheme::File);
78/// ```
79///
80/// # Incorrect Usage
81///
82/// ```ignore
83/// // BAD: Never compare service_name() for routing
84/// if K::service_name() == "VFS" { ... } // WRONG!
85///
86/// // BAD: Never use as escape hatch
87/// fn get_any_service(name: &str) { ... } // WRONG!
88/// ```
89///
90/// # Example
91///
92/// ```ignore
93/// use reovim_kernel::api::v1::ServiceKey;
94///
95/// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
96/// pub enum VfsScheme {
97/// File,
98/// Memory,
99/// Ssh,
100/// }
101///
102/// impl ServiceKey for VfsScheme {
103/// fn service_name() -> &'static str { "VFS" }
104/// }
105/// ```
106pub trait ServiceKey: Hash + Eq + Clone + Send + Sync + 'static {
107 /// Human-readable service name for error messages ONLY.
108 ///
109 /// **NOT for comparison or routing.** See trait-level docs.
110 fn service_name() -> &'static str;
111}
112
113// ============================================================================
114// Unique Service Registry (one provider per type)
115// ============================================================================
116
117/// Registry for unique services - one provider wins per service type.
118///
119/// Uses `TypeId` internally for type-safe lookup. Each service type can have
120/// at most one registered provider; registering a new provider replaces the
121/// existing one.
122///
123/// # Thread Safety
124///
125/// All operations are protected by `RwLock`, allowing concurrent reads with
126/// exclusive writes.
127///
128/// # Example
129///
130/// ```ignore
131/// use reovim_kernel::api::v1::{Service, ServiceRegistry};
132/// use std::sync::Arc;
133///
134/// struct MyCompositor;
135/// impl Service for MyCompositor {}
136///
137/// let registry = ServiceRegistry::new();
138/// registry.register(Arc::new(MyCompositor));
139///
140/// let compositor = registry.get::<MyCompositor>();
141/// assert!(compositor.is_some());
142/// ```
143pub struct ServiceRegistry {
144 services: RwLock<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>,
145}
146
147impl ServiceRegistry {
148 /// Create a new empty service registry.
149 #[must_use]
150 pub fn new() -> Self {
151 Self {
152 services: RwLock::new(HashMap::new()),
153 }
154 }
155
156 /// Register a unique service (replaces existing if any).
157 ///
158 /// # Arguments
159 ///
160 /// * `service` - The service instance wrapped in `Arc`
161 pub fn register<T: Service>(&self, service: Arc<T>) {
162 let type_id = TypeId::of::<T>();
163 self.services.write().insert(type_id, service);
164 }
165
166 /// Get a unique service by type.
167 ///
168 /// Returns `None` if no service of type `T` is registered.
169 #[must_use]
170 pub fn get<T: Service>(&self) -> Option<Arc<T>> {
171 let type_id = TypeId::of::<T>();
172 self.services
173 .read()
174 .get(&type_id)
175 .and_then(|any| any.clone().downcast::<T>().ok())
176 }
177
178 /// Get required service or panic.
179 ///
180 /// # Panics
181 ///
182 /// Panics with `FATAL: No provider for {name}` if no service is registered.
183 ///
184 /// # Arguments
185 ///
186 /// * `name` - Human-readable service name for the error message
187 #[must_use]
188 pub fn get_required<T: Service>(&self, name: &str) -> Arc<T> {
189 self.get::<T>()
190 .unwrap_or_else(|| panic!("FATAL: No provider for {name}"))
191 }
192
193 /// Get or create a keyed service registry.
194 ///
195 /// This is a convenience method for managing [`MultiServiceRegistry`] instances.
196 /// If a registry of type `R` doesn't exist, creates and registers a new one.
197 ///
198 /// # Type Parameters
199 ///
200 /// * `R` - The `MultiServiceRegistry` type (must implement `Service + Default`)
201 #[must_use]
202 pub fn get_or_create<R: Service + Default>(&self) -> Arc<R> {
203 if let Some(registry) = self.get::<R>() {
204 return registry;
205 }
206
207 // Create new registry
208 let registry = Arc::new(R::default());
209 self.register(registry.clone());
210 registry
211 }
212}
213
214impl Default for ServiceRegistry {
215 fn default() -> Self {
216 Self::new()
217 }
218}
219
220impl fmt::Debug for ServiceRegistry {
221 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222 let count = self.services.read().len();
223 f.debug_struct("ServiceRegistry")
224 .field("registered_services", &count)
225 .finish()
226 }
227}
228
229// ============================================================================
230// Multi Service Registry (multiple providers with typed key lookup)
231// ============================================================================
232
233/// Registry for keyed services - multiple providers with typed key-based lookup.
234///
235/// Generic mechanism in kernel, typed keys defined in drivers.
236///
237/// # Type Safety
238///
239/// Uses `K: ServiceKey` bound to ensure only proper service keys can be used.
240/// The [`ServiceKey`] trait provides:
241/// - Compile-time enforcement (arbitrary types rejected)
242/// - Built-in service name for error messages
243/// - Self-documenting API
244///
245/// # Example
246///
247/// ```ignore
248/// use reovim_kernel::api::v1::{MultiServiceRegistry, ServiceKey};
249///
250/// // In driver: define typed key implementing ServiceKey
251/// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
252/// pub enum VfsScheme { File, Memory, Ssh }
253///
254/// impl ServiceKey for VfsScheme {
255/// fn service_name() -> &'static str { "VFS" }
256/// }
257///
258/// // In driver: define type alias with typed key
259/// pub type VfsProviderRegistry = MultiServiceRegistry<VfsScheme, dyn VfsDriver>;
260///
261/// // Usage
262/// let registry = VfsProviderRegistry::new();
263/// registry.register(VfsScheme::File, Arc::new(local_fs_provider));
264/// let provider = registry.get(&VfsScheme::File);
265/// ```
266pub struct MultiServiceRegistry<K: ServiceKey, T: ?Sized> {
267 providers: RwLock<HashMap<K, Arc<T>>>,
268}
269
270impl<K: ServiceKey, T: ?Sized + Send + Sync + 'static> MultiServiceRegistry<K, T> {
271 /// Create a new empty keyed service registry.
272 #[must_use]
273 pub fn new() -> Self {
274 Self {
275 providers: RwLock::new(HashMap::new()),
276 }
277 }
278
279 /// Register a provider for a typed key.
280 ///
281 /// Replaces any existing provider for the same key.
282 ///
283 /// # Arguments
284 ///
285 /// * `key` - The typed service key
286 /// * `provider` - The provider instance wrapped in `Arc`
287 pub fn register(&self, key: K, provider: Arc<T>) {
288 self.providers.write().insert(key, provider);
289 }
290
291 /// Get provider by typed key.
292 ///
293 /// Returns `None` if no provider is registered for the key.
294 #[must_use]
295 pub fn get(&self, key: &K) -> Option<Arc<T>> {
296 self.providers.read().get(key).cloned()
297 }
298
299 /// Get required provider or panic.
300 ///
301 /// Uses `K::service_name()` for the error message automatically.
302 ///
303 /// # Panics
304 ///
305 /// Panics with `FATAL: No {service_name} provider for {key:?}` if not found.
306 #[must_use]
307 pub fn get_required(&self, key: &K) -> Arc<T>
308 where
309 K: fmt::Debug,
310 {
311 self.get(key)
312 .unwrap_or_else(|| panic!("FATAL: No {} provider for {:?}", K::service_name(), key))
313 }
314
315 /// List all registered keys.
316 #[must_use]
317 pub fn keys(&self) -> Vec<K> {
318 self.providers.read().keys().cloned().collect()
319 }
320
321 /// List all registered providers.
322 #[must_use]
323 pub fn values(&self) -> Vec<Arc<T>> {
324 self.providers.read().values().cloned().collect()
325 }
326
327 /// Check if a provider is registered for the given key.
328 #[must_use]
329 pub fn contains(&self, key: &K) -> bool {
330 self.providers.read().contains_key(key)
331 }
332
333 /// Get the number of registered providers.
334 #[must_use]
335 pub fn len(&self) -> usize {
336 self.providers.read().len()
337 }
338
339 /// Check if the registry is empty.
340 #[must_use]
341 pub fn is_empty(&self) -> bool {
342 self.providers.read().is_empty()
343 }
344}
345
346impl<K: ServiceKey, T: ?Sized + Send + Sync + 'static> Default for MultiServiceRegistry<K, T> {
347 fn default() -> Self {
348 Self::new()
349 }
350}
351
352// Implement Service so MultiServiceRegistry can be stored in ServiceRegistry
353impl<K: ServiceKey, T: ?Sized + Send + Sync + 'static> Service for MultiServiceRegistry<K, T> {}
354
355impl<K: ServiceKey + fmt::Debug, T: ?Sized + Send + Sync + 'static> fmt::Debug
356 for MultiServiceRegistry<K, T>
357{
358 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
359 let keys: Vec<_> = self.keys();
360 f.debug_struct("MultiServiceRegistry")
361 .field("service", &K::service_name())
362 .field("keys", &keys)
363 .finish()
364 }
365}
366
367// ============================================================================
368// Tests
369// ============================================================================