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.