Skip to main content

appcore_capabilities/
registry.rs

1// =============================================================================
2//        #######
3//     ###       ###     F: registry.rs
4//    ##   ## ##   ##    P: AppCore-Runtime
5//         ## ##
6//                       C: 2026/07/22 15:41:18 by dnettoRaw
7//    ##   ## ##   ##    U: 2026/07/22 15:41:18 by dnettoRaw
8//      ###########      S: 1.0.1-rc.8
9// =============================================================================
10
11use crate::{
12    CapabilityError, CapabilityRequest, CapabilityResponse, CapabilityResult,
13    LocalCapabilityHandler,
14};
15use appcore_core::{CapabilityDescriptor, CapabilityName};
16use std::collections::HashMap;
17use std::sync::Arc;
18
19/// Registered local capability descriptor and its handler.
20#[derive(Clone)]
21pub struct LocalCapabilityProvider {
22    descriptor: CapabilityDescriptor,
23    handler: Arc<dyn LocalCapabilityHandler>,
24}
25
26impl std::fmt::Debug for LocalCapabilityProvider {
27    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28        f.debug_struct("LocalCapabilityProvider")
29            .field("descriptor", &self.descriptor)
30            .finish_non_exhaustive()
31    }
32}
33
34impl LocalCapabilityProvider {
35    pub(crate) fn new(
36        descriptor: CapabilityDescriptor,
37        handler: Arc<dyn LocalCapabilityHandler>,
38    ) -> Self {
39        Self {
40            descriptor,
41            handler,
42        }
43    }
44
45    /// Returns the immutable descriptor advertised by this provider.
46    pub fn descriptor(&self) -> &CapabilityDescriptor {
47        &self.descriptor
48    }
49
50    /// Reports the current handler health state.
51    pub fn is_healthy(&self) -> bool {
52        self.handler.is_healthy()
53    }
54
55    /// Delegates a request to the registered handler.
56    pub fn handle(&self, request: &CapabilityRequest) -> CapabilityResult<CapabilityResponse> {
57        self.handler.handle(request)
58    }
59}
60
61/// In-process registry of local capability handlers.
62#[derive(Debug, Clone, Default)]
63pub struct CapabilityRegistry {
64    local: HashMap<CapabilityName, LocalCapabilityProvider>,
65}
66
67impl CapabilityRegistry {
68    /// Creates an empty registry.
69    pub fn new() -> Self {
70        Self::default()
71    }
72
73    /// Registers an owned local handler.
74    pub fn register_handler<H>(&mut self, handler: H) -> CapabilityResult<()>
75    where
76        H: LocalCapabilityHandler + 'static,
77    {
78        self.register_shared_handler(Arc::new(handler))
79    }
80
81    /// Registers a shared local handler.
82    pub fn register_shared_handler(
83        &mut self,
84        handler: Arc<dyn LocalCapabilityHandler>,
85    ) -> CapabilityResult<()> {
86        let descriptor = handler.descriptor();
87        if descriptor.version.is_empty() || descriptor.version.len() > 256 {
88            return Err(CapabilityError::HandlerRejected(
89                "invalid_descriptor_version_length".into(),
90            ));
91        }
92        if self.local.contains_key(&descriptor.name) {
93            return Err(CapabilityError::HandlerAlreadyRegistered(
94                descriptor.name.clone(),
95            ));
96        }
97        if self.local.len() >= 4096 {
98            return Err(CapabilityError::HandlerRejected(
99                "local_registry_capacity_exceeded".into(),
100            ));
101        }
102        self.local.insert(
103            descriptor.name.clone(),
104            LocalCapabilityProvider::new(descriptor, handler),
105        );
106        Ok(())
107    }
108
109    /// Returns the local provider registered for a capability.
110    pub fn get(&self, capability: &CapabilityName) -> Option<&LocalCapabilityProvider> {
111        self.local.get(capability)
112    }
113
114    /// Returns descriptors for all registered local providers.
115    /// Use [`Self::iter_descriptors`] when owned copies are unnecessary.
116    pub fn descriptors(&self) -> Vec<CapabilityDescriptor> {
117        self.local
118            .values()
119            .map(|provider| provider.descriptor.clone())
120            .collect()
121    }
122
123    /// Borrows descriptors without allocating or cloning them.
124    /// Iteration order is unspecified, as with [`Self::descriptors`].
125    pub fn iter_descriptors(&self) -> impl ExactSizeIterator<Item = &CapabilityDescriptor> {
126        self.local.values().map(LocalCapabilityProvider::descriptor)
127    }
128}