From fd280d5c8519cbc5184a189c5e6aa6799874e8cc Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Tue, 10 May 2022 08:49:47 +0200 Subject: [PATCH 1/7] Make `can::Id` usable as key in BTreeMap and HashMap by implementing `Ord` and `Hash` --- src/can/id.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/can/id.rs b/src/can/id.rs index 720e3a104..21207b408 100644 --- a/src/can/id.rs +++ b/src/can/id.rs @@ -1,7 +1,7 @@ //! CAN Identifiers. /// Standard 11-bit CAN Identifier (`0..=0x7FF`). -#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] pub struct StandardId(u16); impl StandardId { @@ -40,7 +40,7 @@ impl StandardId { } /// Extended 29-bit CAN Identifier (`0..=1FFF_FFFF`). -#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] pub struct ExtendedId(u32); impl ExtendedId { @@ -85,7 +85,7 @@ impl ExtendedId { } /// A CAN Identifier (standard or extended). -#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] pub enum Id { /// Standard 11-bit Identifier (`0..=0x7FF`). Standard(StandardId), From bcdca453b20aca8c02ceb84fb6a8f082c24b6817 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Tue, 10 May 2022 10:13:35 +0200 Subject: [PATCH 2/7] Manually implement `Ord` according to CAN bus arbitration rules --- src/can/id.rs | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/can/id.rs b/src/can/id.rs index 21207b408..f0d35600b 100644 --- a/src/can/id.rs +++ b/src/can/id.rs @@ -85,7 +85,7 @@ impl ExtendedId { } /// A CAN Identifier (standard or extended). -#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Id { /// Standard 11-bit Identifier (`0..=0x7FF`). Standard(StandardId), @@ -94,6 +94,30 @@ pub enum Id { Extended(ExtendedId), } +impl Ord for Id { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + let split_id = |id: &Id| { + let (standard_id_part, ide_bit, extended_id_part) = match id { + Id::Standard(StandardId(x)) => (*x, 0, 0), + Id::Extended(x) => ( + x.standard_id().0, + 1, + x.0 & ((1 << 18) - 1), // Bit ID-17 to ID-0 + ), + }; + (standard_id_part, ide_bit, extended_id_part) + }; + + split_id(self).cmp(&split_id(other)) + } +} + +impl PartialOrd for Id { + fn partial_cmp(&self, other: &Id) -> Option { + Some(self.cmp(other)) + } +} + impl From for Id { #[inline] fn from(id: StandardId) -> Self { @@ -157,4 +181,20 @@ mod tests { StandardId::new((ExtendedId::MAX.0 >> 18) as u16) ); } + + #[test] + fn cmp_standard() { + assert!(StandardId::MAX < StandardId::ZERO); + } + + #[test] + fn cmp_extended() { + assert!(ExtendedId::MAX < ExtendedId::ZERO); + } + + #[test] + fn cmp_id() { + assert!(Id::Standard(StandardId::MAX) < Id::Standard(StandardId::ZERO)); + assert!(Id::Extended(ExtendedId::MAX) < Id::Extended(ExtendedId::ZERO)); + } } From 6a164ee34ed44ba837edb855f02b76ddcaf1b575 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Tue, 10 May 2022 13:31:24 +0200 Subject: [PATCH 3/7] Updated tests --- src/can/id.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/can/id.rs b/src/can/id.rs index f0d35600b..890c73d8d 100644 --- a/src/can/id.rs +++ b/src/can/id.rs @@ -194,7 +194,12 @@ mod tests { #[test] fn cmp_id() { - assert!(Id::Standard(StandardId::MAX) < Id::Standard(StandardId::ZERO)); - assert!(Id::Extended(ExtendedId::MAX) < Id::Extended(ExtendedId::ZERO)); + assert!(StandardId::ZERO < StandardId::MAX); + assert!(ExtendedId::ZERO < ExtendedId::MAX); + + assert!(Id::Standard(StandardId::ZERO) < Id::Extended(ExtendedId::ZERO)); + assert!(Id::Extended(ExtendedId::ZERO) < Id::Extended(ExtendedId::MAX)); + assert!(Id::Extended(ExtendedId((1 << 11) - 1)) < Id::Standard(StandardId(1))); + assert!(Id::Standard(StandardId(1)) < Id::Extended(ExtendedId::MAX)); } } From b14a937a9cd00f21397dcf900b600140e0c25998 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 11 May 2022 07:33:34 +0200 Subject: [PATCH 4/7] Remove old tests --- src/can/id.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/can/id.rs b/src/can/id.rs index 890c73d8d..307ecb35b 100644 --- a/src/can/id.rs +++ b/src/can/id.rs @@ -182,16 +182,6 @@ mod tests { ); } - #[test] - fn cmp_standard() { - assert!(StandardId::MAX < StandardId::ZERO); - } - - #[test] - fn cmp_extended() { - assert!(ExtendedId::MAX < ExtendedId::ZERO); - } - #[test] fn cmp_id() { assert!(StandardId::ZERO < StandardId::MAX); From da3b64ea31e669552c6d97f31a742139552f2e29 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 11 May 2022 08:01:19 +0200 Subject: [PATCH 5/7] Add documentation and update changelog --- CHANGELOG.md | 2 ++ src/can/id.rs | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ca79a8ec..66c6a760a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- Implement `PartialOrd`, `Ord`, `Hash` for `can::StandardId`, `can::ExtendedId` and `can::Id` according to CAN bus arbitration rules + ## [v1.0.0-alpha.8] - 2022-04-15 *** This is (also) an alpha release with breaking changes (sorry) *** diff --git a/src/can/id.rs b/src/can/id.rs index 307ecb35b..f9c79c351 100644 --- a/src/can/id.rs +++ b/src/can/id.rs @@ -94,6 +94,20 @@ pub enum Id { Extended(ExtendedId), } +/// Implement `Ord` according to the CAN arbitration rules +/// +/// When performing arbitration, frames are looked at bit for bit starting +/// from the beginning. A bit with the value 0 is dominant and a bit with +/// value of 1 is recessive. +/// +/// When two devices are sending frames at the same time, as soon as the first +/// bit is found which differs, the frame with the corresponding dominant +/// 0 bit will win and get to send the rest of the frame. +/// +/// This implementation of `Ord` for `Id` will take this into consideration +/// and when comparing two different instances of `Id` the "smallest" will +/// always be the id which would form the most dominant frame, all other +/// things being equal. impl Ord for Id { fn cmp(&self, other: &Self) -> core::cmp::Ordering { let split_id = |id: &Id| { From b657a93a657367e6be129fb08edc56f35079f087 Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Fri, 13 May 2022 22:02:17 +0200 Subject: [PATCH 6/7] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66c6a760a..9a845f0a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added - Implement `PartialOrd`, `Ord`, `Hash` for `can::StandardId`, `can::ExtendedId` and `can::Id` according to CAN bus arbitration rules ## [v1.0.0-alpha.8] - 2022-04-15 From 0c066ad8bd1cf43ba22b007e42adccb6b463f6cd Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Fri, 13 May 2022 22:02:25 +0200 Subject: [PATCH 7/7] Update src/can/id.rs --- src/can/id.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/can/id.rs b/src/can/id.rs index f9c79c351..88ddaa0a2 100644 --- a/src/can/id.rs +++ b/src/can/id.rs @@ -106,7 +106,7 @@ pub enum Id { /// /// This implementation of `Ord` for `Id` will take this into consideration /// and when comparing two different instances of `Id` the "smallest" will -/// always be the id which would form the most dominant frame, all other +/// always be the ID which would form the most dominant frame, all other /// things being equal. impl Ord for Id { fn cmp(&self, other: &Self) -> core::cmp::Ordering {