How to design warnings in trait-based abstraction APIs?
⚓ Rust 📅 2026-06-25 👤 surdeus 👁️ 2I have a use case where, from my point of view, I'm in a realm in-between Result::Ok and Result::Err. It may be an xy-problem, so here's the background:
I have a function that takes a fade duration (e.g. when dimming a Zigbee device over time).
Now I have an abstraction API that allows passing in an arbitrary std::time::Duration.
However, Zigbee only allows a u16 of deciseconds, so not all durations are supported.
I decided to not fail the function on the implementation for Zigbee with an Err and bailing out, but to cap the duration to the maximum possible value.
The capped (or non-capped) actual value that has been sent via Zigbee is then returned.
So my function currently looks like this:
/// Trait for devices that can be dimmed.
pub trait Dimming: Protocol {
/// Dim the light to the specified value.
///
/// # Returns
///
/// Returns the actual duration that may have been capped by the implementor.
///
/// # Errors
///
/// Returns an [`Error`](Self::Error) if dimming fails.
fn dim(
&self,
destination: <Self as Types>::Destination,
percent: Percent,
rate: Duration,
) -> impl Future<Output = Result<Duration, Self::Error>> + Send;
}
However, I'm not completely satisfied with this design, as this suggests that everything went fine when the value was, in fact, capped.
On the other hand, I don't think that bailing out with an error is the right choice either.
How would you go about conveying to the caller, that the call succeeded but that there was a problem?
Would you do that at all, or would you error out?
If so, how could we convey to the caller what values could be acceptable - it is different for different functions of the respective trait(s) (some are u8, some u16 deciseconds).
6 posts - 4 participants
🏷️ Rust_feed