Skip to main content

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// ============================================================================