Description
PR #852 refactors ServerDeviceFeatureOutput from a struct with Option fields to an enum stored in SmallVecEnumMap. As part of this, the From<ServerDeviceFeatureOutput> for DeviceFeatureOutput impl is replaced by a macro-generated version that no longer filters disabled outputs.
Commit bc88d3d specifically added .filter(|x| !x.disabled()) to the old From impl to prevent disabled outputs from leaking to clients. The new macro-generated From impl converts all variants unconditionally.
The filtering responsibility has moved to as_device_feature(), which correctly calls .filter(|o| !o.is_disabled()) before the conversion. This works today since as_device_feature() is the only call path. However, the public From impl is now a footgun — any future code calling .into() on a &ServerDeviceFeatureOutput directly will bypass the disabled filter.
Suggested fix
Either:
- Restore filtering in the
From impl (or make it a named method instead of From to signal it's not a simple conversion)
- Make the
From impl pub(crate) to limit the blast radius
- Document the invariant that
as_device_feature() is the only safe conversion path
Context
Description
PR #852 refactors
ServerDeviceFeatureOutputfrom a struct withOptionfields to an enum stored inSmallVecEnumMap. As part of this, theFrom<ServerDeviceFeatureOutput> for DeviceFeatureOutputimpl is replaced by a macro-generated version that no longer filters disabled outputs.Commit bc88d3d specifically added
.filter(|x| !x.disabled())to the oldFromimpl to prevent disabled outputs from leaking to clients. The new macro-generatedFromimpl converts all variants unconditionally.The filtering responsibility has moved to
as_device_feature(), which correctly calls.filter(|o| !o.is_disabled())before the conversion. This works today sinceas_device_feature()is the only call path. However, the publicFromimpl is now a footgun — any future code calling.into()on a&ServerDeviceFeatureOutputdirectly will bypass the disabled filter.Suggested fix
Either:
Fromimpl (or make it a named method instead ofFromto signal it's not a simple conversion)Fromimplpub(crate)to limit the blast radiusas_device_feature()is the only safe conversion pathContext