studiole_command/services/
command_registry.rs1use crate::prelude::*;
2
3pub struct CommandRegistry<T: ICommandInfo> {
5 handlers: HashMap<TypeId, T::Handler>,
6}
7
8impl<T: ICommandInfo> CommandRegistry<T> {
9 #[must_use]
11 pub fn new() -> Self {
12 Self {
13 handlers: HashMap::default(),
14 }
15 }
16
17 #[allow(clippy::as_conversions)]
19 pub fn register<
20 R: Executable + Send + Sync + 'static,
21 H: Execute<R, R::Response, R::ExecutionError>,
22 >(
23 &mut self,
24 handler: Arc<H>,
25 ) where
26 Arc<H>: Into<T::Handler>,
27 {
28 let request_type = TypeId::of::<R>();
29 self.handlers.insert(request_type, handler.into());
30 }
31
32 #[allow(clippy::as_conversions)]
34 pub fn resolve<R: Executable + Send + Sync + 'static>(
35 &self,
36 request: R,
37 ) -> Result<T::Command, Report<QueueError>> {
38 let request_type = TypeId::of::<R>();
39 let handler = self
40 .handlers
41 .get(&request_type)
42 .ok_or_else(|| {
43 Report::new(QueueError::NoMatch)
44 .attach_with("request_type", || String::from(type_name::<R>()))
45 .attach("request", request.to_string())
46 })?
47 .clone();
48 let command = T::Command::new(request, handler);
49 Ok(command)
50 }
51}
52
53pub trait RegisterHandlers: ICommandInfo {
59 fn register_handlers(
61 services: &ServiceProvider,
62 ) -> impl Future<Output = Result<CommandRegistry<Self>, Report<ResolveError>>> + Send
63 where
64 Self: Sized;
65}
66
67impl<T: RegisterHandlers + 'static> FromServicesAsync for CommandRegistry<T> {
68 type Error = ResolveError;
69
70 async fn from_services_async(services: &ServiceProvider) -> Result<Self, Report<Self::Error>> {
71 T::register_handlers(services).await
72 }
73}
74
75#[derive(Debug, Error)]
77pub enum QueueError {
78 #[error("Unable to match request to command")]
79 NoMatch,
80 #[error("Unable to match request to command")]
81 IncorrectCommandType,
82}