Remove Magic Numbers for Enum IDs and replace with constants#37
Remove Magic Numbers for Enum IDs and replace with constants#37parth-20-07 wants to merge 6 commits into
Conversation
- uses procedural macros to use the determinant of enum to convert number<>enum Signed-off-by: Parth Patel <parth.pmech@gmail.com>
Signed-off-by: Parth Patel <parth.pmech@gmail.com>
There was a problem hiding this comment.
Pull Request Overview
This PR refactors the codebase to eliminate magic numbers by introducing named constants for enum discriminants and implementing automatic conversion traits using the num_enum crate.
Key changes:
- Introduces
num_enumprocedural macros for unit enums to auto-deriveIntoandTryFromimplementations - Adds named constants for non-unit enum types to replace magic numbers in conversion methods
- Updates error handling to use
try_frominstead of infalliblefromconversions where appropriate
Reviewed Changes
Copilot reviewed 18 out of 19 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| Cargo.toml | Adds num_enum dependency (version 0.7.4) for enum conversion macros |
| src/lib.rs | Applies num_enum derives to RoutineControlSubFunction and DtcSettings, adds test cases, removes manual From/TryFrom implementations |
| src/error.rs | Adds new error variant InvalidUDSMessageValue for wire format validation |
| src/service.rs | Adds constants for service type IDs and response offsets, refactors methods to use constants |
| src/services/routine_control.rs | Changes from infallible from to try_from with error handling |
| src/services/control_dtc_settings.rs | Changes from infallible from to try_from with error handling |
| src/services/request_file_transfer.rs | Adds constants for file operation modes, updates match statements |
| src/services/read_dtc_information.rs | Adds extensive constants for DTC subfunction IDs, refactors decode/encode methods, introduces response_id() helper |
| src/common/* | Multiple files updated with constants replacing magic numbers in enums and conversion methods |
| src/common/communication_type.rs | Applies num_enum derives, removes manual trait implementations |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| UserDefMemoryDTCSnapshotRecordByDTCNumRecord::decode(reader)?.unwrap(), | ||
| ))) | ||
| } | ||
| Self::USER_DEF_MEMORY_DTC_EXT_DATA_RECORD_BY_DTC_NUMBER => todo!(), |
There was a problem hiding this comment.
The decode implementation contains a todo!() macro that will panic at runtime if this case is encountered. This represents incomplete functionality that should be implemented before merging.
| Self::USER_DEF_MEMORY_DTC_EXT_DATA_RECORD_BY_DTC_NUMBER => todo!(), | |
| Self::USER_DEF_MEMORY_DTC_EXT_DATA_RECORD_BY_DTC_NUMBER => { | |
| Ok(Some(Self::UserDefMemoryDTCExtDataRecordByDTCNumberList( | |
| UserDefMemoryDTCExtDataRecordByDTCNumRecord::decode(reader)?.unwrap(), | |
| ))) | |
| } |
There was a problem hiding this comment.
Incorrect Suggestion. DTC Is not implemented for decode.
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 18 out of 19 changed files in this pull request and generated no new comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
Signed-off-by: Parth Patel <parth.pmech@gmail.com>
Signed-off-by: Parth Patel <parth.pmech@gmail.com>
Signed-off-by: Parth Patel <parth.pmech@gmail.com>
Signed-off-by: Parth Patel <parth.pmech@gmail.com>
b9f0a86 to
bcbec50
Compare
kymikoloco
left a comment
There was a problem hiding this comment.
The negative response codes and DIDs could really benefit from an upgrade of the num_enum macro, I really don't know how to feel about not just using the discriminant and replacing everything with screaming caps.
I especially don't think that replacing the ranges with 2 constant variables is the right way to go about it.
| VehicleManufacturerECUSoftwareNumber = 0xF188, | ||
| VehicleManufacturerECUSoftwareVersionNumber = 0xF189, | ||
| SystemSupplierIdentifier = 0xF18A, | ||
| BootSoftwareIdentification = Self::BOOT_SOFTWARE_IDENTIFICATION, |
There was a problem hiding this comment.
This is one of those instances that I would like to be set as the raw value in the struct definition just for the easy readability of no screaming caps. I kind of wish num_enum supported variant types, because they support a single enum as multiple numbers via the alternatives, but not storing them?
I don't know, I don't think these count as magic numbers, and I would like to use a different scheme for the DIDs and RIDs (like our own macro, or Zach's suggestion that we just add the derive macros to the uds_protocol_derive crate, which may allow us to implement this missing feature.
Can we just revert the changes to the DIDs for now? I am not a fan of the change specifically to these.
| UDSIdentifier::ISO_SAE_RESERVED_START..=UDSIdentifier::ISO_SAE_RESERVED_END => { | ||
| UDSIdentifier::ISOSAEReserved(value) | ||
| } | ||
| UDSIdentifier::VEHICLE_MANUFACTURER_SPECIFIC_START | ||
| ..=UDSIdentifier::VEHICLE_MANUFACTURER_SPECIFIC_END => { | ||
| UDSIdentifier::VehicleManufacturerSpecific(value) | ||
| } |
There was a problem hiding this comment.
The constants in the range match alone looks really gnarly from a readability standpoint and I don't think we should be doing this 0_0
| /// | ||
| /// Will be 0 after a successful [`ClearDiagnosticInformation`](crate::services::ClearDiagnosticInformation) service | ||
| TestFailed, | ||
| TestFailed = Self::TEST_FAILED, |
There was a problem hiding this comment.
This doesn't have any magic numbers due to the fact the bitmask attribute handles all the bitwise operations. I don't think we need constants in this enum, it could cause someone to cast to u8 to do checks instead of using the newtype to do all bitwise comparisons
| fn test_incorrect_discriminant() { | ||
| let raw_discriminant: u8 = 0x04; | ||
|
|
||
| let id_from_discriminant = RoutineControlSubFunction::try_from(raw_discriminant) | ||
| .err() | ||
| .unwrap() | ||
| .to_string(); | ||
|
|
||
| assert_eq!( | ||
| id_from_discriminant, | ||
| Error::InvalidUDSMessageValue(raw_discriminant).to_string() | ||
| ); |
There was a problem hiding this comment.
The discriminant is a programming term, not something we need to test or even call out. You're testing an incorrect value.
| #[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)] | ||
| #[num_enum(error_type(name = crate::Error, constructor = Error::InvalidUDSMessageValue))] | ||
| #[repr(u8)] | ||
| pub enum DtcSettings { | ||
| On, | ||
| Off, | ||
| On = 0x01, | ||
| Off = 0x02, | ||
| } |
| #[repr(u8)] | ||
| pub enum UdsServiceType { |
There was a problem hiding this comment.
Must do: Why was this not a TryFromPrimitive? We could probably greatly simplify this and use the num_enum alternatives configuration since each of these can contain 2 values, the request and the response.
Then the functions here can use try_from and add the constant offset in a single call.
| Self::ISO_RESERVED_START..=Self::ISO_RESERVED_END => Ok(Self::ISOSAEReserved(value)), | ||
| Self::VEHICLE_MANUFACTURER_START..=Self::VEHICLE_MANUFACTURER_END => { | ||
| Ok(Self::VehicleManufacturerSpecific(value)) | ||
| } | ||
| Self::SYSTEM_SUPPLIER_START..=Self::SYSTEM_SUPPLIER_END => { | ||
| Ok(Self::SystemSupplierSpecific(value)) | ||
| } |
There was a problem hiding this comment.
Might be able to do stuff like this:
fn is_iso_reserved(val: u8) -> bool {
(0x00 == val)
|| (0x06..=0x3F).contains(&val)
|| (0x7F == val)
}
match value {
v if is_iso_reserved(v) => Self::ISOSAEReserved(v),
other_vals => pseudocode,
}|
@kymikoloco @zheylmun Closing this PR due to closed discussions on the constants requirements. Can be reopened in future if new discussions are initiated. |

Implementation:
num_enumprocedural macros to use the determinant of unit enum to implement into, try_from methods.Closes: https://github.com/luminartech/dft/issues/328
Signed-off-by: Parth Patel parth.pmech@gmail.com