diff --git a/overwatch-rs/src/overwatch/handle.rs b/overwatch-rs/src/overwatch/handle.rs index ee5dcae..1b52d82 100644 --- a/overwatch-rs/src/overwatch/handle.rs +++ b/overwatch-rs/src/overwatch/handle.rs @@ -70,7 +70,10 @@ impl OverwatchHandle { } #[instrument(skip(self))] - pub async fn update_settings(&self, settings: S::Settings) { + pub async fn update_settings(&self, settings: S::Settings) + where + S::Settings: Send, + { if let Err(e) = self .sender .send(OverwatchCommand::Settings(SettingsCommand(Box::new( diff --git a/overwatch-rs/src/overwatch/mod.rs b/overwatch-rs/src/overwatch/mod.rs index 54a2b24..b1e9555 100644 --- a/overwatch-rs/src/overwatch/mod.rs +++ b/overwatch-rs/src/overwatch/mod.rs @@ -55,15 +55,15 @@ impl From for Error { type FinishOverwatchSignal = (); /// Marker trait for settings related elements -pub type AnySettings = Box; +pub type AnySettings = Box; /// An overwatch run anything that implements this trait /// An implementor of this trait would have to handle the inner [`ServiceCore`](crate::services::ServiceCore) #[async_trait] -pub trait Services: Sized + Send + Sync { +pub trait Services: Sized { /// Inner [`ServiceCore::Settings`](crate::services::ServiceCore) grouping type. /// Normally this will be a settings object that group all the inner services settings. - type Settings: Debug + Send + 'static; + type Settings: Debug + 'static; // 'static is required for cast to `AnySetting` /// Spawn a new instance of the Services object /// It returns a `(ServiceId, Runtime)` where Runtime is the `tokio::runtime::Runtime` attached for each @@ -108,7 +108,7 @@ pub const OVERWATCH_THREAD_NAME: &str = "Overwatch"; impl OverwatchRunner where - S: Services + 'static, + S: Services + Send + 'static, { /// Start the Overwatch runner process /// It creates the `tokio::runtime::Runtime`, initialize the [`Services`] and start listening for diff --git a/overwatch-rs/src/services/handle.rs b/overwatch-rs/src/services/handle.rs index fb3573a..af392ca 100644 --- a/overwatch-rs/src/services/handle.rs +++ b/overwatch-rs/src/services/handle.rs @@ -115,7 +115,12 @@ impl ServiceStateHandle { } } -impl ServiceRunner { +impl ServiceRunner +where + S::State: Send + Sync + 'static, + S::StateOperator: Send + 'static, + S: ServiceCore + 'static, +{ /// Spawn the service main loop and handle it lifecycle /// Return a handle to abort execution manually diff --git a/overwatch-rs/src/services/mod.rs b/overwatch-rs/src/services/mod.rs index 3ec51a4..e107b38 100644 --- a/overwatch-rs/src/services/mod.rs +++ b/overwatch-rs/src/services/mod.rs @@ -41,7 +41,7 @@ pub trait ServiceData { /// Main trait for Services initialization and main loop hook #[async_trait] -pub trait ServiceCore: ServiceData + Send + Sized + 'static { +pub trait ServiceCore: Sized + ServiceData { /// Initialize the service with the given state fn init(service_state: ServiceStateHandle) -> Result; diff --git a/overwatch-rs/src/services/state.rs b/overwatch-rs/src/services/state.rs index 56e5351..24ceefa 100644 --- a/overwatch-rs/src/services/state.rs +++ b/overwatch-rs/src/services/state.rs @@ -15,7 +15,7 @@ use tracing::error; /// It defines what is needed for a service state to be initialized. /// Need what set of settings information is required for it to be initialized [`ServiceState::Settings`] /// which usually is bound to the service itself [`crate::services::ServiceData::Settings`] -pub trait ServiceState: Sized + Send + Sync + 'static { +pub trait ServiceState: Sized { /// Settings object that the state can be initialized from type Settings; /// Errors that can occur during state initialization @@ -27,7 +27,7 @@ pub trait ServiceState: Sized + Send + Sync + 'static { /// A state operator is an entity that can handle a state in a point of time /// to perform any operation based on it. #[async_trait] -pub trait StateOperator: Send { +pub trait StateOperator { /// The type of state that the operator can handle type StateInput: ServiceState; /// Operator initialization method. Can be implemented over some subset of settings @@ -38,7 +38,13 @@ pub trait StateOperator: Send { /// Operator that doesn't perform any operation upon state update #[derive(Copy)] -pub struct NoOperator(PhantomData); +pub struct NoOperator(PhantomData<*const StateInput>); + +// NoOperator does not actually hold anything and is thus Sync. +// Note that we don't use PhantomData as that would +// suggest we indeed hold an instance of StateInput, see +// https://doc.rust-lang.org/std/marker/struct.PhantomData.html#ownership-and-the-drop-check +unsafe impl Send for NoOperator {} // auto derive introduces unnecessary Clone bound on T impl Clone for NoOperator { @@ -48,7 +54,7 @@ impl Clone for NoOperator { } #[async_trait] -impl StateOperator for NoOperator { +impl StateOperator for NoOperator { type StateInput = StateInput; fn from_settings(_settings: Settings) -> Self { @@ -69,7 +75,7 @@ impl Clone for NoState { } } -impl ServiceState for NoState { +impl ServiceState for NoState { type Settings = Settings; type Error = crate::DynError; @@ -82,15 +88,15 @@ impl ServiceState for NoState { /// Receiver part of the state handling mechanism. /// A state handle watches a stream of incoming states and triggers the attached operator handling /// method over it. -pub struct StateHandle> { +pub struct StateHandle { watcher: StateWatcher, operator: Operator, } // auto derive introduces unnecessary Clone bound on T -impl> Clone for StateHandle +impl Clone for StateHandle where - Operator: Clone, + O: Clone, { fn clone(&self) -> Self { Self { @@ -159,12 +165,8 @@ where } } -impl StateHandle -where - S: ServiceState + Clone, - Operator: StateOperator, -{ - pub fn new(initial_state: S, operator: Operator) -> (Self, StateUpdater) { +impl StateHandle { + pub fn new(initial_state: S, operator: O) -> (Self, StateUpdater) { let (sender, receiver) = channel(initial_state); let watcher = StateWatcher { receiver }; let updater = StateUpdater { @@ -173,7 +175,13 @@ where (Self { watcher, operator }, updater) } +} +impl StateHandle +where + S: ServiceState + Clone + Send + Sync + 'static, + Operator: StateOperator, +{ /// Wait for new state updates and run the operator handling method pub async fn run(self) { let Self {