Repository navigation
Description
Proposal
Problem statement
Integer primitives have functions such as overflowing_neg() for numeric negation with controlled overflow. These functions are currently missing from the core::num::NonZeroI{8,16,32,64} types.
Motivation, use-cases
Non-zero integers are frequently used to represent error codes from low-level OS APIs, because these APIs use 0 to indicate non-error. Some APIs use signed error codes as a form of namespacing, such as internal/public (FreeBSD) or kernel/userspace (Linux).
For example, the FUSE protocol uses userspace error codes (positive non-zero) but negates them when sending an error frame to the kernel.
// old
let (neg, _) = err.get().overflowing_neg();
let wire_neg = unsafe { NonZeroI32::new_unchecked(neg) };
// new
let (wire_neg, _) = err.overflowing_neg();Solution sketches
Since the primitive integer types already have *_neg() functions, and negation can't return zero for non-zero inputs, writing wrappers for the non-zero integers is straightforward.
pub const fn is_negative(self) -> bool {
self.get().is_negative()
}
pub const fn checked_neg(self) -> Option<$Ty> {
if let Some(result) = self.get().checked_neg() {
return Some(unsafe { $Ty::new_unchecked(result) });
}
None
}
pub const fn overflowing_neg(self) -> ($Ty, bool) {
let (result, overflow) = self.get().overflowing_neg();
((unsafe { $Ty::new_unchecked(result) }), overflow)
}
pub const fn saturating_neg(self) -> $Ty {
if let Some(result) = self.checked_neg() {
return result;
}
unsafe { $Ty::new_unchecked(<$Int>::MAX) }
}
pub const fn wrapping_neg(self) -> $Ty {
let result = self.get().wrapping_neg();
unsafe { $Ty::new_unchecked(result) }
}Links and related work
rust-lang/rust#89065
rust-lang/rust#84186
What happens now?
This issue is part of the libs-api team API change proposal process. Once this issue is filed the libs-api team will review open proposals in its weekly meeting. You should receive feedback within a week or two.
Activity
jmillikin commentedon Sep 18, 2022
Proposed implementation: jmillikin/upstream__rust@a807a2d
Docs screenshots:
cuviper commentedon Sep 18, 2022
How about
trait Negfor the operator?jmillikin commentedon Sep 18, 2022
It's easy to implement, but my understanding is that trait impls for two stable types can't be marked
unstabledue to rust-lang/rust#55436.thomcc commentedon Sep 18, 2022
That's not a deal-breaker if the trait implementation is sensible/desirable.
jmillikin commentedon Sep 18, 2022
I agree that
Negwould be useful, have no strong opinion on the exact details of the stabilization process, and would be happy to do whatever the Rust libs team recommends in this case.scottmcm commentedon Sep 26, 2022
Given that the signed nonzero types already have things like
checked_absandoverflowing_absandsaturating_muland such, adding things likechecked_negandsaturating_negseem well covered by existing precedent, so if you want to send a PR for the methods as unstable, you canr? @scottmcmon that and I'll approve it. (They probably just weren't done originally because they don't make sense on the unsigned versions.)Trait impls can't go in unstable, though, so that at least should be a different PR, and I'll leave it for a real libs-api member to comment on it.
jmillikin commentedon Sep 27, 2022
OK, I've filed PR rust-lang/rust#102341 to implement
NegforNonZeroI*.To avoid merge conflicts, I'll send a second PR for the negation functions once that first one lands.
scottmcm commentedon Sep 27, 2022
Traits take at least 10 days for FCP, so that PR will take much longer to land than one for unstable inherent methods.
jmillikin commentedon Sep 27, 2022
Interesting. OK, filed rust-lang/rust#102342 to add the new methods. Once one of them merges I'll rebase the second one.
Rollup merge of rust-lang#102342 - jmillikin:nonzero-negation, r=scot…
Rollup merge of rust-lang#102342 - jmillikin:nonzero-negation, r=scot…
Rollup merge of #102342 - jmillikin:nonzero-negation, r=scottmcm
Rollup merge of rust-lang#102341 - jmillikin:nonzero-impl-neg, r=dtolnay
Rollup merge of rust-lang#111186 - jmillikin:nonzero-is-positive, r=d…
Auto merge of rust-lang#111044 - jmillikin:nonzero-negation, r=dtolnay
Auto merge of #111044 - jmillikin:nonzero-negation, r=dtolnay
Rollup merge of #111186 - jmillikin:nonzero-is-positive, r=dtolnay
Auto merge of #111044 - jmillikin:nonzero-negation, r=dtolnay
Auto merge of #111044 - jmillikin:nonzero-negation, r=dtolnay
Auto merge of #111044 - jmillikin:nonzero-negation, r=dtolnay
Auto merge of #111044 - jmillikin:nonzero-negation, r=dtolnay