rust_supervisor/role/adapter/service.rs
1//! Service role adapter.
2//!
3//! The adapter owns the bridge from [`ServiceRole`] lifecycle methods to the
4//! existing [`TaskFactory`](crate::task::factory::TaskFactory) runtime contract.
5
6use crate::role::context::service::ServiceContext;
7use crate::role::result::service::ServiceError;
8use crate::role::traits::service::ServiceRole;
9use crate::task::context::TaskContext;
10use crate::task::factory::{BoxTaskFuture, Service, TaskResult};
11use std::sync::Arc;
12use tokio::sync::Mutex;
13
14/// Adapter that turns a service role into a task factory service.
15pub struct ServiceRoleAdapter<T> {
16 /// Role instance protected across runtime task starts.
17 role: Arc<Mutex<T>>,
18}
19
20impl<T> ServiceRoleAdapter<T>
21where
22 T: ServiceRole,
23{
24 /// Creates a service role adapter.
25 ///
26 /// # Arguments
27 ///
28 /// - `role`: Service role instance that owns user lifecycle state.
29 ///
30 /// # Returns
31 ///
32 /// Returns an adapter that implements the task factory service contract.
33 ///
34 /// # Examples
35 ///
36 /// ```
37 /// use rust_supervisor::role::adapter::service::ServiceRoleAdapter;
38 /// use rust_supervisor::role::context::service::ServiceContext;
39 /// use rust_supervisor::role::result::service::ServiceResult;
40 /// use rust_supervisor::role::traits::service::ServiceRole;
41 ///
42 /// struct ExampleService;
43 ///
44 /// impl ServiceRole for ExampleService {
45 /// async fn run(&mut self, ctx: &ServiceContext) -> ServiceResult<()> {
46 /// let _ = ctx;
47 /// Ok(())
48 /// }
49 /// }
50 ///
51 /// let _adapter = ServiceRoleAdapter::new(ExampleService);
52 /// ```
53 pub fn new(role: T) -> Self {
54 Self {
55 role: Arc::new(Mutex::new(role)),
56 }
57 }
58}
59
60impl<T> Service for ServiceRoleAdapter<T>
61where
62 T: ServiceRole,
63{
64 /// Builds one task future for the adapted service role.
65 fn call(&self, ctx: TaskContext) -> BoxTaskFuture {
66 let role = self.role.clone();
67 let service_context = ServiceContext::new(ctx);
68 Box::pin(async move {
69 let mut role = role.lock().await;
70 run_service_lifecycle(&mut *role, &service_context).await
71 })
72 }
73}
74
75/// Runs the service lifecycle and maps role errors into task results.
76///
77/// # Arguments
78///
79/// - `role`: Service role implementation.
80/// - `ctx`: Service-specific context passed to lifecycle methods.
81///
82/// # Returns
83///
84/// Returns a [`TaskResult`] consumed by the runtime.
85async fn run_service_lifecycle<T>(role: &mut T, ctx: &ServiceContext) -> TaskResult
86where
87 T: ServiceRole,
88{
89 if let Err(error) = role.init(ctx).await {
90 return service_error_to_task_result(error);
91 }
92 if let Err(error) = role.run(ctx).await {
93 return service_error_to_task_result(error);
94 }
95 if let Err(error) = role.shutdown(ctx).await {
96 return service_error_to_task_result(error);
97 }
98 if ctx.is_shutdown_requested() {
99 TaskResult::Cancelled
100 } else {
101 TaskResult::Succeeded
102 }
103}
104
105/// Converts a service error into a failed task result.
106///
107/// # Arguments
108///
109/// - `error`: Service role error returned by a lifecycle method.
110///
111/// # Returns
112///
113/// Returns [`TaskResult::Failed`] with a typed task failure payload.
114fn service_error_to_task_result(error: ServiceError) -> TaskResult {
115 TaskResult::Failed(error.into_task_failure())
116}