diff --git a/CHANGELOG.md b/CHANGELOG.md index a41bfd6..e96d252 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,8 @@ and its version numbers follow [Semantic Versioning](https://semver.org/). - `RuntimeHandle` now supports forwarding arbitrary control messages, including `RuntimeControlMessage::Custom(...)`, via `control(...)` and `custom(...)` helpers (`#20`). +- `RuntimeControlMessage::Custom(...)` is now clone-safe and no longer panics + when cloned (`#27`). ### Removed - Unused aliases and imports producing compiler warnings. diff --git a/src/runtime_guard.rs b/src/runtime_guard.rs index aa81be1..507c8b9 100644 --- a/src/runtime_guard.rs +++ b/src/runtime_guard.rs @@ -156,7 +156,7 @@ impl RuntimeGuard { where T: std::any::Any + Send + Sync + 'static, { - self.control(RuntimeControlMessage::Custom(Box::new(message))) + self.control(RuntimeControlMessage::Custom(Arc::new(message))) } /// **Busy-wait** helper for tests and demos. diff --git a/src/runtime_handle.rs b/src/runtime_handle.rs index 6eae41e..43dfc20 100644 --- a/src/runtime_handle.rs +++ b/src/runtime_handle.rs @@ -44,7 +44,7 @@ impl RuntimeHandle { where T: std::any::Any + Send + Sync + 'static, { - self.control(RuntimeControlMessage::Custom(Box::new(message))) + self.control(RuntimeControlMessage::Custom(Arc::new(message))) } } diff --git a/src/runtime_process.rs b/src/runtime_process.rs index 3b5060d..5c089a5 100644 --- a/src/runtime_process.rs +++ b/src/runtime_process.rs @@ -68,28 +68,14 @@ pub enum ProcessOperation { /// wildcard arm (`_`) when pattern-matching so that new variants introduced in /// future releases do not break compilation. #[non_exhaustive] -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum RuntimeControlMessage { /// Trigger a *hot reload*. Reload, /// Request a *graceful shutdown*. Shutdown, /// User-defined message for custom extensions. - Custom(Box), -} - -impl Clone for RuntimeControlMessage { - /// Manual implementation is required because the enum is - /// `#[non_exhaustive]`; remember to update this when adding new variants. - fn clone(&self) -> Self { - match self { - RuntimeControlMessage::Reload => RuntimeControlMessage::Reload, - RuntimeControlMessage::Shutdown => RuntimeControlMessage::Shutdown, - RuntimeControlMessage::Custom(_) => { - panic!("Cloning `Custom` control messages is not supported") - } - } - } + Custom(Arc), } impl Runnable for Arc diff --git a/tests/integration.rs b/tests/integration.rs index 5123778..96359b2 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -313,6 +313,22 @@ async fn test_runtime_handle_custom_control_message_is_delivered() { } } +#[test] +fn test_runtime_control_message_custom_clone_is_safe() { + let msg = RuntimeControlMessage::Custom(Arc::new(7_u8)); + let cloned = msg.clone(); + + match cloned { + RuntimeControlMessage::Custom(payload) => { + let value = payload + .downcast::() + .expect("expected u8 custom payload"); + assert_eq!(*value, 7_u8); + } + _ => panic!("expected custom control message"), + } +} + #[tokio::test] async fn test_reload_dispatch_is_parallel() { let mut manager = ProcessManager::new();