From dc9ad9028b58597cee87eef2f6647e7149cfc278 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Mon, 6 Oct 2025 02:01:04 +0800 Subject: Add service module with macros and action framework - Create new vcs_service crate for handling service actions - Add vcs_service_macros crate for procedural macros - Add vcs_test module with action framework integration - Implement Action and ActionPool traits for service operations --- crates/service/src/action_pool.rs | 108 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 crates/service/src/action_pool.rs (limited to 'crates/service/src/action_pool.rs') diff --git a/crates/service/src/action_pool.rs b/crates/service/src/action_pool.rs new file mode 100644 index 0000000..0a1a6c7 --- /dev/null +++ b/crates/service/src/action_pool.rs @@ -0,0 +1,108 @@ +use tcp_connection::error::TcpTargetError; + +use crate::action::{Action, ActionContext}; + +/// A pool of registered actions that can be processed by name +pub struct ActionPool { + /// HashMap storing action name to action implementation mapping + actions: std::collections::HashMap<&'static str, Box>, +} + +impl ActionPool { + /// Creates a new empty ActionPool + pub fn new() -> Self { + Self { + actions: std::collections::HashMap::new(), + } + } + + /// Registers an action type with the pool + /// + /// Usage: + /// ``` + /// action_pool.register::(); + /// ``` + pub fn register(&mut self) + where + A: Action + Send + Sync + 'static, + Args: serde::de::DeserializeOwned + Send + Sync + 'static, + Return: serde::Serialize + Send + Sync + 'static, + { + let action_name = A::action_name(); + self.actions.insert( + action_name, + Box::new(ActionWrapper::(std::marker::PhantomData)), + ); + } + + /// Processes an action by name with given context and arguments + /// + /// Usage: + /// ``` + /// let result = action_pool.process::("my_action", context, args).await?; + /// ``` + pub async fn process<'a, Args, Return>( + &'a self, + action_name: &'a str, + context: ActionContext, + args: Args, + ) -> Result + where + Args: serde::de::DeserializeOwned + Send + 'static, + Return: serde::Serialize + Send + 'static, + { + if let Some(action) = self.actions.get(action_name) { + let result = action.process_erased(context, Box::new(args)).await?; + let result = *result + .downcast::() + .map_err(|_| TcpTargetError::Unsupported("InvalidArguments".to_string()))?; + Ok(result) + } else { + Err(TcpTargetError::Unsupported("InvalidAction".to_string())) + } + } +} + +/// Trait for type-erased actions that can be stored in ActionPool +trait ActionErased: Send + Sync { + /// Processes the action with type-erased arguments and returns type-erased result + fn process_erased( + &self, + context: ActionContext, + args: Box, + ) -> std::pin::Pin< + Box< + dyn std::future::Future, TcpTargetError>> + + Send, + >, + >; +} + +/// Wrapper struct that implements ActionErased for concrete Action types +struct ActionWrapper(std::marker::PhantomData<(A, Args, Return)>); + +impl ActionErased for ActionWrapper +where + A: Action + Send + Sync, + Args: serde::de::DeserializeOwned + Send + Sync + 'static, + Return: serde::Serialize + Send + Sync + 'static, +{ + fn process_erased( + &self, + context: ActionContext, + args: Box, + ) -> std::pin::Pin< + Box< + dyn std::future::Future, TcpTargetError>> + + Send, + >, + > { + Box::pin(async move { + let args = *args + .downcast::() + .map_err(|_| TcpTargetError::Unsupported("InvalidArguments".to_string()))?; + let result = A::process(context, args).await?; + Ok(Box::new(result) as Box) + }) + } +} -- cgit