From 0ec7fdf11bc2dc7c41267253770c49c622568f41 Mon Sep 17 00:00:00 2001 From: Lucien Cartier-Tilet Date: Sat, 3 Jan 2026 22:34:36 +0100 Subject: [PATCH] feat(domain): implement RelayId newtype with validation Implement smart constructor that validates relay IDs are within valid range (1-8 for 8-channel relay controller). Add accessor method as_u8() for safe access to inner value. Add comprehensive documentation to satisfy clippy requirements. TDD green phase: Tests from T017 now pass. Ref: T018 (specs/001-modbus-relay-control/tasks.md) --- backend/src/domain/relay/controler.rs | 7 +++++ backend/src/domain/relay/mod.rs | 2 ++ backend/src/domain/relay/types/mod.rs | 2 ++ .../relay/{types.rs => types/relayid.rs} | 29 +++++++++++++++++++ specs/001-modbus-relay-control/tasks.md | 2 +- 5 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 backend/src/domain/relay/controler.rs create mode 100644 backend/src/domain/relay/types/mod.rs rename backend/src/domain/relay/{types.rs => types/relayid.rs} (65%) diff --git a/backend/src/domain/relay/controler.rs b/backend/src/domain/relay/controler.rs new file mode 100644 index 0000000..50bc63e --- /dev/null +++ b/backend/src/domain/relay/controler.rs @@ -0,0 +1,7 @@ +/// Errors that can occur during relay controller operations. +#[derive(Debug, thiserror::Error)] +pub enum ControllerError { + /// The provided relay ID is outside the valid range (1-8). + #[error("Invalid relay ID: {0}")] + InvalidRelayId(u8), +} diff --git a/backend/src/domain/relay/mod.rs b/backend/src/domain/relay/mod.rs index 0f64921..4e63f39 100644 --- a/backend/src/domain/relay/mod.rs +++ b/backend/src/domain/relay/mod.rs @@ -7,3 +7,5 @@ pub mod repository; /// Domain types for relay identification and control. pub mod types; +/// Controller error types for relay operations. +pub mod controler; diff --git a/backend/src/domain/relay/types/mod.rs b/backend/src/domain/relay/types/mod.rs new file mode 100644 index 0000000..d5467b3 --- /dev/null +++ b/backend/src/domain/relay/types/mod.rs @@ -0,0 +1,2 @@ +mod relayid; +pub use relayid::RelayId; diff --git a/backend/src/domain/relay/types.rs b/backend/src/domain/relay/types/relayid.rs similarity index 65% rename from backend/src/domain/relay/types.rs rename to backend/src/domain/relay/types/relayid.rs index 21dc380..835ccd0 100644 --- a/backend/src/domain/relay/types.rs +++ b/backend/src/domain/relay/types/relayid.rs @@ -1,3 +1,5 @@ +use crate::domain::relay::controler::ControllerError; + /// Unique identifier for a relay in the system. /// /// Uses the newtype pattern to provide type safety and prevent mixing relay IDs @@ -7,6 +9,33 @@ #[repr(transparent)] pub struct RelayId(u8); +impl RelayId { + /// Creates a new `RelayId` from a relay channel number. + /// + /// This is a smart constructor that validates the relay ID is within the + /// valid range (1-8) for an 8-channel relay controller. + /// + /// # Errors + /// + /// Returns `ControllerError::InvalidRelayId` if the ID is not in the range 1-8. + pub const fn new(id: u8) -> Result { + if id > 0 && id < 9 { + Ok(Self(id)) + } else { + Err(ControllerError::InvalidRelayId(id)) + } + } + + /// Returns the inner `u8` value of the relay ID. + /// + /// This accessor method provides access to the underlying relay channel number. + #[must_use] + pub const fn as_u8(&self) -> u8 { + self.0 + } + +} + impl std::fmt::Display for RelayId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.0.fmt(f) diff --git a/specs/001-modbus-relay-control/tasks.md b/specs/001-modbus-relay-control/tasks.md index 70f955a..bddaa4c 100644 --- a/specs/001-modbus-relay-control/tasks.md +++ b/specs/001-modbus-relay-control/tasks.md @@ -211,7 +211,7 @@ - **File**: src/domain/relay.rs - **Complexity**: Low | **Uncertainty**: Low -- [ ] **T018** [US1] [TDD] Implement RelayId newtype with validation +- [x] **T018** [US1] [TDD] Implement RelayId newtype with validation - #[repr(transparent)] newtype wrapping u8 - Constructor validates 1..=8 range - Implement Display, Debug, Clone, Copy, PartialEq, Eq