Skip to content

Commit 90bdc5c

Browse files
authoredJul 1, 2024··
Add iter and from_repr support, switch to strum crate (#11)
* Add `from_repr(u8) -> Option<Enum>` to all `Enum`s * this is a better method than `try_from` because `Option<T>` is likely to be smaller than `Result<T, &str>` * Add `Enum::iter()` - enabled by default with the `iter` feature * Switch to [strum crate](https://crates.io/crates/strum) * Do not expose internal macros * Fail to compile if none of the `with-kwp2000`, `with-obd2`, or `with-uds` features are enabled.
1 parent 02bab4f commit 90bdc5c

28 files changed

+157
-157
lines changed
 

‎Cargo.toml

+4-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ categories = ["embedded", "no-std", "encoding", "parsing"]
1111
rust-version = "1.61.0"
1212

1313
[features]
14-
default = ["std", "display", "with-kwp2000", "with-obd2", "with-uds"]
14+
default = ["std", "iter", "display", "with-kwp2000", "with-obd2", "with-uds"]
1515
# Include support for std library. Without this feature, uses `no_std` attribute
1616
std = []
17+
# Add Enum::iter() implementation for all enums
18+
iter = []
1719
# Add Display implementation for all enums, using doc comments as display strings
1820
display = ["dep:displaydoc"]
1921
# Include support for Keyword protocol 2000 - ISO142330
@@ -24,8 +26,8 @@ with-obd2 = []
2426
with-uds = []
2527

2628
[dependencies]
27-
enum2repr = "0.1"
2829
displaydoc = { version = "0.2", optional = true }
30+
strum = { version = "0.26.3", features = ["derive"] }
2931

3032
[dev-dependencies]
3133
cargo-husky = { version = "1", features = ["user-hooks"], default-features = false }

‎README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pull request.
1919
## Usage
2020

2121
All values are presented as Rust `enum`, and can be converted to/from their underlying numeric values using
22-
the `From<T>` and `TryFrom<u8>` traits. Most enums also have a corresponding `...Byte` enums as `ByteWrapper<T>` to
22+
the `T::from_repr(u8)` and `u8::from(value)`. Most enums also have a corresponding `...Byte` enums as `ByteWrapper<T>` to
2323
handle the non-standard `Extended(u8)` values in addition to the defined `Standand(T)` ones.
2424

2525
```rust

‎justfile

+4-3
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ clean:
1010

1111
# Run cargo clippy
1212
clippy:
13-
cargo clippy --bins --tests --lib --benches --examples -- -D warnings
14-
cargo clippy --no-default-features -- -D warnings
13+
cargo clippy --workspace --bins --tests --lib --benches --examples -- -D warnings
14+
cargo clippy --no-default-features --features with-uds -- -D warnings
1515

1616
# Test code formatting
1717
test-fmt:
@@ -34,8 +34,9 @@ check:
3434
# Run all tests
3535
test:
3636
RUSTFLAGS='-D warnings' cargo test
37+
RUSTFLAGS='-D warnings' cargo test --no-default-features --features with-kwp2000
38+
RUSTFLAGS='-D warnings' cargo test --no-default-features --features with-obd2
3739
RUSTFLAGS='-D warnings' cargo test --no-default-features --features with-uds
38-
RUSTFLAGS='-D warnings' cargo test --no-default-features
3940

4041
# Test documentation
4142
test-doc:

‎src/kwp2000/commands.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
4-
5-
enum_wrapper!(kwp2000, KwpCommand, KwpCommandByte);
1+
crate::utils::enum_wrapper!(kwp2000, KwpCommand, KwpCommandByte);
62

73
/// KWP Command Service IDs.
84
///
95
/// Note. This does not cover both the 'Reserved' range (0x87-0xB9) and
106
/// 'System supplier specific' range (0xBA-0xBF)
117
#[repr(u8)]
12-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
8+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
9+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
1310
pub enum KwpCommand {
1411
/// Start or change ECU diagnostic session mode.
1512
StartDiagnosticSession = 0x10,

‎src/kwp2000/errors.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
4-
5-
enum_wrapper!(kwp2000, KwpError, KwpErrorByte);
1+
crate::utils::enum_wrapper!(kwp2000, KwpError, KwpErrorByte);
62

73
/// KWP2000 Error definitions
84
#[repr(u8)]
9-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
5+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
6+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
107
pub enum KwpError {
118
/// ECU rejected the request for unknown reason
129
GeneralReject = 0x10,

‎src/kwp2000/reset_types.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
//! This service requests the ECU to perform a reset
22
3-
use enum2repr::EnumRepr;
4-
5-
use crate::enum_wrapper;
6-
7-
enum_wrapper!(kwp2000, ResetType, ResetTypeByte);
3+
crate::utils::enum_wrapper!(kwp2000, ResetType, ResetTypeByte);
84

95
/// ECU Reset types
106
///
@@ -15,7 +11,8 @@ enum_wrapper!(kwp2000, ResetType, ResetTypeByte);
1511
/// |[`ResetType::PowerOnReset`]|Mandatory|
1612
/// |[`ResetType::NonVolatileMemoryReset`]|Optional|
1713
#[repr(u8)]
18-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
14+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
15+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
1916
#[cfg_attr(feature = "display", derive(displaydoc::Display))]
2017
pub enum ResetType {
2118
/// Simulates a power off/on reset of the ECU.

‎src/kwp2000/routine_exit_status.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
4-
5-
enum_wrapper!(kwp2000, RoutineExitStatus, RoutineExitStatusByte);
1+
crate::utils::enum_wrapper!(kwp2000, RoutineExitStatus, RoutineExitStatusByte);
62

73
#[repr(u8)]
8-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
4+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
5+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
96
pub enum RoutineExitStatus {
107
/// Normal exit with results available
118
NormalExitWithResults = 0x61,

‎src/kwp2000/session_types.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
4-
5-
enum_wrapper!(kwp2000, KwpSessionType, KwpSessionTypeByte);
1+
crate::utils::enum_wrapper!(kwp2000, KwpSessionType, KwpSessionTypeByte);
62

73
/// KWP2000 diagnostic session type
84
///
@@ -16,7 +12,8 @@ enum_wrapper!(kwp2000, KwpSessionType, KwpSessionTypeByte);
1612
/// |[`KwpSessionType::Passive`] | Optional (Only intended for ECU development) |
1713
/// |[`KwpSessionType::ExtendedDiagnostics`] | Mandatory |
1814
#[repr(u8)]
19-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
15+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
16+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
2017
pub enum KwpSessionType {
2118
/// Normal session. The ECU will typically boot in this state.
2219
/// In this mode, only non-intrusive functions are supported.

‎src/lib.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
#![cfg_attr(feature = "default", doc = include_str!("../README.md"))]
22
#![cfg_attr(not(feature = "std"), no_std)]
33

4+
// It makes no sense to use this crate without at least one of the core features enabled
5+
#[cfg(not(any(feature = "with-kwp2000", feature = "with-obd2", feature = "with-uds")))]
6+
compile_error!(
7+
"At least one of the features `with-kwp2000`, `with-obd2`, or `with-uds` must be enabled!"
8+
);
9+
410
#[cfg(feature = "with-kwp2000")]
511
pub mod kwp2000;
612
#[cfg(feature = "with-obd2")]
@@ -22,12 +28,14 @@ mod tests {
2228
use crate::ByteWrapper::{Extended, Standard};
2329

2430
assert_eq!(UdsCommandByte::from(0x11), Standard(ECUReset));
31+
assert_eq!(UdsCommand::from_repr(0x11), Some(ECUReset));
2532
assert_eq!(UdsCommand::try_from(0x11), Ok(ECUReset));
2633
assert_eq!(ECUReset as u8, 0x11);
2734
assert_eq!(u8::from(ECUReset), 0x11);
2835
assert_eq!(u8::from(Standard(ECUReset)), 0x11);
2936
assert_eq!(UdsCommandByte::from(ECUReset), Standard(ECUReset));
3037

38+
assert!(UdsCommand::from_repr(0x42).is_none());
3139
assert!(UdsCommand::try_from(0x42).is_err());
3240
assert_eq!(UdsCommandByte::from(0x42), Extended(0x42));
3341
}

‎src/obd2/command_2nd_air_status.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
4-
5-
enum_wrapper!(
1+
crate::utils::enum_wrapper!(
62
obd2,
73
CommandedSecondaryAirStatus,
84
CommandedSecondaryAirStatusByte
95
);
106

117
/// Commanded secondary air status for PID 12
128
#[repr(u8)]
13-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
9+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
10+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
1411
#[cfg_attr(feature = "display", derive(displaydoc::Display))]
1512
pub enum CommandedSecondaryAirStatus {
1613
/// Upstream

‎src/obd2/commands.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
4-
5-
enum_wrapper!(obd2, Obd2Command, Obd2CommandByte);
1+
crate::utils::enum_wrapper!(obd2, Obd2Command, Obd2CommandByte);
62

73
/// OBD2 Command Service IDs
84
#[repr(u8)]
9-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
5+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
6+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
107
#[cfg_attr(feature = "display", derive(displaydoc::Display))]
118
pub enum Obd2Command {
129
/// Service 01 - Show current data

‎src/obd2/data_pids.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
4-
5-
enum_wrapper!(obd2, DataPid, DataPidByte);
1+
crate::utils::enum_wrapper!(obd2, DataPid, DataPidByte);
62

73
/// OBD2 data PIDs used for Service 01 and 02
84
#[repr(u8)]
9-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
5+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
6+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
107
pub enum DataPid {
118
PidSupport0120 = 0x00,
129
StatusSinceDTCCleared = 0x01,

‎src/obd2/errors.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
4-
5-
enum_wrapper!(obd2, Obd2Error, Obd2ErrorByte);
1+
crate::utils::enum_wrapper!(obd2, Obd2Error, Obd2ErrorByte);
62

73
/// OBD2 Error definitions
84
#[repr(u8)]
9-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
5+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
6+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
107
#[cfg_attr(feature = "display", derive(displaydoc::Display))]
118
pub enum Obd2Error {
129
/// ECU general reject

‎src/obd2/fuel_system_status.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
4-
5-
enum_wrapper!(obd2, FuelSystemStatus, FuelSystemStatusByte);
1+
crate::utils::enum_wrapper!(obd2, FuelSystemStatus, FuelSystemStatusByte);
62

73
/// Fuel system status enumeration for PID 03
84
#[repr(u8)]
9-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
5+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
6+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
107
#[cfg_attr(feature = "display", derive(displaydoc::Display))]
118
pub enum FuelSystemStatus {
129
/// The motor is off

‎src/obd2/fuel_types.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
4-
5-
enum_wrapper!(obd2, FuelTypeCoding, FuelTypeCodingByte);
1+
crate::utils::enum_wrapper!(obd2, FuelTypeCoding, FuelTypeCodingByte);
62

73
/// Fuel type coding for PID 51
84
#[allow(non_camel_case_types)]
95
#[repr(u8)]
10-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
6+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
7+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
118
#[cfg_attr(feature = "display", derive(displaydoc::Display))]
129
pub enum FuelTypeCoding {
1310
/// Fuel type unavailable

‎src/obd2/obd_standard.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
4-
5-
enum_wrapper!(obd2, ObdStandard, ObdStandardByte);
1+
crate::utils::enum_wrapper!(obd2, ObdStandard, ObdStandardByte);
62

73
/// OBD Standard for PID 1C
84
#[allow(non_camel_case_types)]
95
#[repr(u8)]
10-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
6+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
7+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
118
#[cfg_attr(feature = "display", derive(displaydoc::Display))]
129
#[allow(clippy::doc_markdown)]
1310
pub enum ObdStandard {

‎src/obd2/service09.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
4-
5-
enum_wrapper!(obd2, Service09Pid, Service09PidByte);
1+
crate::utils::enum_wrapper!(obd2, Service09Pid, Service09PidByte);
62

73
/// OBD2 service 09 (Request vehicle information) PIDs
84
#[repr(u8)]
9-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
5+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
6+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
107
#[cfg_attr(feature = "display", derive(displaydoc::Display))]
118
pub enum Service09Pid {
129
/// VIN message count (Only for LIN)

‎src/uds/comm_level.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
4-
5-
enum_wrapper!(uds, CommunicationLevel, CommunicationLevelByte);
1+
crate::utils::enum_wrapper!(uds, CommunicationLevel, CommunicationLevelByte);
62

73
/// Communication level toggle
84
#[repr(u8)]
9-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
5+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
6+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
107
pub enum CommunicationLevel {
118
/// This value indicates that the reception and transmission of messages
129
/// shall be enabled for the specified communicationType.

‎src/uds/commands.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
4-
5-
enum_wrapper!(uds, UdsCommand, UdsCommandByte);
1+
crate::utils::enum_wrapper!(uds, UdsCommand, UdsCommandByte);
62

73
/// UDS Command Service IDs
84
#[repr(u8)]
9-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
5+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
6+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
107
#[cfg_attr(feature = "display", derive(displaydoc::Display))]
118
pub enum UdsCommand {
129
/// The client requests to control a diagnostic session with a server(s).

‎src/uds/errors.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
41
#[cfg(doc)]
52
use crate::uds::SecurityOperation;
3+
use crate::utils::enum_wrapper;
64

75
enum_wrapper!(uds, UdsError, UdsErrorByte);
86

97
/// UDS Error definitions
108
#[repr(u8)]
11-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
9+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
10+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
1211
pub enum UdsError {
1312
/// ECU rejected the request (No specific error)
1413
GeneralReject = 0x10,

‎src/uds/read_dtc_information.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
41
#[cfg(doc)]
52
use crate::uds::UdsCommand;
3+
use crate::utils::enum_wrapper;
64

75
enum_wrapper!(uds, DtcSubFunction, DtcSubFunctionByte);
86

97
/// [`UdsCommand::ReadDTCInformation`] sub-function definitions
108
#[repr(u8)]
11-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
9+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
10+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
1211
#[cfg_attr(feature = "display", derive(displaydoc::Display))]
1312
#[allow(clippy::doc_markdown)]
1413
pub enum DtcSubFunction {

‎src/uds/reset_types.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
4-
5-
enum_wrapper!(uds, ResetType, ResetTypeByte);
1+
crate::utils::enum_wrapper!(uds, ResetType, ResetTypeByte);
62

73
/// Reset ECU subcommand
84
#[repr(u8)]
9-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
5+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
6+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
107
pub enum ResetType {
118
/// Signals the ECU to perform a hard-reset,
129
/// simulating a forceful power off/on cycle

‎src/uds/routine.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
4-
5-
enum_wrapper!(uds, RoutineControlType, RoutineControlTypeByte);
1+
crate::utils::enum_wrapper!(uds, RoutineControlType, RoutineControlTypeByte);
62

73
/// UDS Routine (0x31) service control types.
84
/// See chapter `14.2 RoutineControl service` in the ISO 14229 spec.
95
#[repr(u8)]
10-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
6+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
7+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
118
pub enum RoutineControlType {
129
/// Launches a routine on the ECU
1310
StartRoutine = 0x01,

‎src/uds/scaling_byte.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
4-
5-
enum_wrapper!(uds, Scaling, ScalingByte);
1+
crate::utils::enum_byte_wrapper!(uds, Scaling, ScalingByte);
2+
crate::utils::enum_impls!(uds, ScalingType);
63

74
/// Scaling high nibble, representing the type of data without its size. The size is given by the low nibble.
85
#[repr(u8)]
9-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
6+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
7+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
108
#[cfg_attr(feature = "display", derive(displaydoc::Display))]
119
pub enum ScalingType {
1210
/// Unsigned numeric integer. Must be followed by 1..4 bytes, given as a low nibble of the byte.
@@ -44,7 +42,7 @@ pub struct Scaling {
4442

4543
impl From<Scaling> for u8 {
4644
fn from(value: Scaling) -> Self {
47-
value.typ as u8 | value.size
45+
value.typ as Self | value.size
4846
}
4947
}
5048

@@ -55,6 +53,12 @@ impl Scaling {
5553
}
5654
(typ as u8 | size).try_into()
5755
}
56+
57+
/// Try to create [Self] from the raw representation
58+
#[must_use]
59+
pub fn from_repr(discriminant: u8) -> Option<Self> {
60+
Scaling::try_from(discriminant).ok()
61+
}
5862
}
5963

6064
impl TryFrom<u8> for Scaling {

‎src/uds/scaling_byte_ext.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
4-
5-
enum_wrapper!(uds, ScalingExtension, ScalingExtensionByte);
1+
crate::utils::enum_wrapper!(uds, ScalingExtension, ScalingExtensionByte);
62

73
/// A macro rule to generate prefix and postfix functions from a single enum
84
macro_rules! generate_enum {
@@ -66,7 +62,8 @@ generate_enum! {
6662
/// Use [`ScalingExtension::get_postfix`] to return the optional postfix of the scaling byte,
6763
/// or [`ScalingExtension::get_prefix`] to return the optional prefix of the scaling byte.
6864
#[repr(u8)]
69-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
65+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
66+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
7067
pub enum ScalingExtension {
7168
/// No unit or presentation
7269
NoUnit = 0x00,

‎src/uds/security_access.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,12 @@
33
//!
44
//! Currently, only default seed/key (0x01/0x02) are supported
55
6-
use enum2repr::EnumRepr;
7-
8-
use crate::enum_wrapper;
9-
10-
enum_wrapper!(uds, SecurityOperation, SecurityOperationByte);
6+
crate::utils::enum_wrapper!(uds, SecurityOperation, SecurityOperationByte);
117

128
/// Security operation request
139
#[repr(u8)]
14-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
10+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
11+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
1512
pub enum SecurityOperation {
1613
/// Asks the ECU for a security seed
1714
RequestSeed = 0x01,

‎src/uds/session_types.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
use enum2repr::EnumRepr;
2-
3-
use crate::enum_wrapper;
4-
5-
enum_wrapper!(uds, UdsSessionType, UdsSessionTypeByte);
1+
crate::utils::enum_wrapper!(uds, UdsSessionType, UdsSessionTypeByte);
62

73
/// UDS Diagnostic session modes. Handled by SID 0x10
84
#[repr(u8)]
9-
#[derive(EnumRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
5+
#[derive(strum::FromRepr, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
6+
#[cfg_attr(feature = "iter", derive(strum::EnumIter))]
107
pub enum UdsSessionType {
118
/// Default diagnostic session mode (ECU is normally in this mode on startup)
129
/// This session type does not require the diagnostic server to sent `TesterPresent` messages

‎src/utils.rs

+63-16
Original file line numberDiff line numberDiff line change
@@ -27,40 +27,85 @@ impl<T: Into<u8>> From<ByteWrapper<T>> for u8 {
2727
}
2828
}
2929

30-
impl<T: TryFrom<u8>> From<u8> for ByteWrapper<T> {
31-
fn from(value: u8) -> Self {
32-
match T::try_from(value) {
33-
Ok(v) => ByteWrapper::Standard(v),
34-
Err(_) => ByteWrapper::Extended(value),
35-
}
36-
}
37-
}
38-
39-
#[macro_export]
4030
macro_rules! enum_wrapper {
4131
($ns:tt, $enum_name:tt, $enum_wrapper:tt) => {
42-
#[doc = concat!("Store a single byte, either as a `Standard(", stringify!($enum_name), ")`, or as an `Extended(u8)`.")]
43-
pub type $enum_wrapper = $crate::ByteWrapper<$enum_name>;
32+
$crate::utils::enum_impls!($ns, $enum_name);
33+
$crate::utils::enum_byte_wrapper!($ns, $enum_name, $enum_wrapper);
34+
};
35+
}
4436

45-
impl From<$crate::$ns::$enum_name> for $crate::$ns::$enum_wrapper {
37+
macro_rules! enum_impls {
38+
($ns:tt, $enum_name:tt) => {
39+
impl TryFrom<u8> for $crate::$ns::$enum_name {
40+
type Error = &'static str;
41+
fn try_from(value: u8) -> Result<Self, Self::Error> {
42+
$crate::$ns::$enum_name::from_repr(value)
43+
.ok_or("Failed to convert enum to numeric value!")
44+
}
45+
}
46+
47+
impl From<$crate::$ns::$enum_name> for u8 {
4648
fn from(value: $crate::$ns::$enum_name) -> Self {
47-
Self::Standard(value)
49+
value as Self
4850
}
4951
}
5052

5153
#[cfg(test)]
52-
mod enum_wrapper_tests {
54+
mod enum_impls_tests {
5355
#[test]
54-
#[allow(non_snake_case)]
5556
fn test_try_from() {
5657
for value in 0x00_u8..=0xFF {
5758
if let Ok(v) = $crate::$ns::$enum_name::try_from(value) {
5859
let enc: u8 = v.into();
5960
assert_eq!(value, enc, "{value:#02X} → {v:?} → {enc:#02X}");
61+
assert_eq!(
62+
$crate::$ns::$enum_name::from_repr(value).unwrap(),
63+
v,
64+
"{value:#02X} → {v:?}"
65+
);
6066
}
6167
}
6268
}
6369

70+
#[test]
71+
#[cfg(feature = "iter")]
72+
fn test_iter() {
73+
use ::strum::IntoEnumIterator as _;
74+
75+
assert_ne!(0, $crate::$ns::$enum_name::iter().count());
76+
for value in $crate::$ns::$enum_name::iter() {
77+
let enc: u8 = value.into();
78+
assert_eq!(value, $crate::$ns::$enum_name::try_from(enc).unwrap());
79+
}
80+
}
81+
}
82+
};
83+
}
84+
85+
macro_rules! enum_byte_wrapper {
86+
($ns:tt, $enum_name:tt, $enum_wrapper:tt) => {
87+
#[doc = concat!("Store a single byte, either as a `Standard(", stringify!($enum_name), ")`, or as an `Extended(u8)`.")]
88+
pub type $enum_wrapper = $crate::ByteWrapper<$enum_name>;
89+
90+
impl From<$crate::$ns::$enum_name> for $crate::$ns::$enum_wrapper {
91+
fn from(value: $crate::$ns::$enum_name) -> Self {
92+
Self::Standard(value)
93+
}
94+
}
95+
96+
// Implementing it as part of the macro because from_repr is not part of a trait
97+
// https://github.com/Peternator7/strum/issues/251
98+
impl From<u8> for $crate::ByteWrapper<$crate::$ns::$enum_name> {
99+
fn from(value: u8) -> Self {
100+
match $crate::$ns::$enum_name::from_repr(value) {
101+
Some(v) => $crate::ByteWrapper::Standard(v),
102+
None => $crate::ByteWrapper::Extended(value),
103+
}
104+
}
105+
}
106+
107+
#[cfg(test)]
108+
mod enum_byte_wrapper_tests {
64109
#[test]
65110
#[allow(non_snake_case)]
66111
fn test_from() {
@@ -73,3 +118,5 @@ macro_rules! enum_wrapper {
73118
}
74119
};
75120
}
121+
122+
pub(crate) use {enum_byte_wrapper, enum_impls, enum_wrapper};

0 commit comments

Comments
 (0)
Please sign in to comment.