fix(hidpp): keep events when a field carries an unknown enum value - #432
fix(hidpp): keep events when a field carries an unknown enum value#432bugprone wants to merge 2 commits into
Conversation
Event listener closures have no error channel, so a single unrecognised field byte made the whole event decode return None — a crown update with an unknown gesture, for example, lost its valid rotation deltas too. Sweep the remaining event decoders (crown, extended_dpi, illumination, rgb_effects) onto the tolerant pattern AprilNEA#381 established, choosing the idiom per how the enum is used: - Event-read-only enums gain a num_enum(catch_all) Other(u8) variant so an unknown wire value carries its raw byte instead of dropping the event. - Lod is also written back to the device via SetDpiParameters, so it must stay a closed enum to keep invalid lift-off values unrepresentable; its event field becomes Option<Lod> instead, leaving the write and response paths strict (unknown values there still surface UnsupportedResponse). Unknown event sub-ids still return None: an unknown event kind has no payload shape to decode, unlike an unknown field within a known event. RawWheelResolution and IlluminationState are masked to their full value range at the call site and cannot fail, so they are left unchanged.
Greptile SummaryThis PR applies the tolerant-decode pattern across the remaining HID++ event decoders so that a single unrecognised enum byte no longer silently drops a whole event. The strategy is consistently applied: enums used only in event reading gain a
Confidence Score: 5/5Safe to merge; the change tightens event-decode robustness without touching any request-encoding or write path. All write-path APIs remain strict (Lod, DpiDirection, PowerModeTarget keep their closed TryFromPrimitive enums), the tolerant paths are gated behind event-only types, and every changed decode position is covered by a 0..=255 totality sweep. The only finding is a stale doc-comment in extended_dpi/event.rs — the code itself is correct. The doc-comment on decode_event in crates/openlogi-hidpp/src/feature/extended_dpi/event.rs still describes the old drop-on-unknown-value behaviour and should be updated. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Raw HID++ event payload] --> B{Known sub-id?}
B -- No --> C[return None]
B -- Yes --> D{Enum field type?}
D -- catch_all FromPrimitive --> E[Known value gets concrete variant, unknown value gets Other byte]
E --> F[Some Event always returned]
D -- Closed TryFromPrimitive --> G{try_from succeeds?}
G -- Yes --> H[field is Some variant]
G -- No --> I[field is None]
H --> J[Some Event with field Some]
I --> K[Some Event with field None]
F --> L[Caller receives event with all sibling fields intact]
J --> L
K --> L
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[Raw HID++ event payload] --> B{Known sub-id?}
B -- No --> C[return None]
B -- Yes --> D{Enum field type?}
D -- catch_all FromPrimitive --> E[Known value gets concrete variant, unknown value gets Other byte]
E --> F[Some Event always returned]
D -- Closed TryFromPrimitive --> G{try_from succeeds?}
G -- Yes --> H[field is Some variant]
G -- No --> I[field is None]
H --> J[Some Event with field Some]
I --> K[Some Event with field None]
F --> L[Caller receives event with all sibling fields intact]
J --> L
K --> L
Reviews (2): Last reviewed commit: "fix(hidpp): keep DpiDirection and PowerM..." | Re-trigger Greptile |
…fety Both are also written back to the device — DpiDirection via the DPI request encoders and PowerModeTarget via set_rgb_cluster_effect — so giving them a catch_all Other(u8) variant would let an unknown value round-trip onto the wire, the same hazard that kept Lod closed. Treat them like Lod: the enum stays closed and only the event field becomes Option. Also add a totality sweep for the ClusterChanged power-mode nibble, which the 2-bit field can carry values the enum does not model.
Summary
Event listener closures have no error channel, so a single unrecognised field byte made a whole event decode return
None— a crown update with an unknown gesture, for example, lost its valid rotation deltas in the same payload. This sweeps the remaining event decoders onto the tolerant pattern #381 established.The idiom is chosen per how each enum is used:
RotationState/ActivityState/CrownGesture/ButtonState,DpiDirection,BrightnessClampedSource,ActivityEventType,PowerModeTarget) gain anum_enum(catch_all) Other(u8)variant, so an unknown wire value carries its raw byte instead of dropping the event.Lodis also written back to the device viaSetDpiParameters, so making itcatch_allwould let an invalid lift-off value be written. It stays a closed enum — keeping illegal values unrepresentable — and only its event field becomesOption<Lod>. The write and response paths stay strict: unknown values there still surfaceUnsupportedResponse.RawWheelResolutionandIlluminationStateare masked to their full value range at the call site and cannot fail, so they are left unchanged.Unknown event sub-ids still return
None: an unknown event kind has no payload shape to decode, unlike an unknown field within a known event.Changes
crates/openlogi-hidpp: tolerant decode for the crown, extended_dpi, illumination, and rgb_effects event decoders;Lodevent field is nowOption<Lod>.Testing
cargo test -p openlogi-hidpp— 161 passed. New totality tests sweep0..=255across each enum field position to prove a known sub-id never drops, plus the two prior "unknown → dropped" tests are flipped to assert the value is preserved. The strict response-path test (rejects_unknown_lod_value) stays green.cargo clippy -p openlogi-hidpp --all-targetsandcargo fmt --checkclean.Fixes #382