Infallible div_ceil for NonZero<unsigned> (original) (raw)

Proposal

Problem statement

The NonZero<T> types currently doesn't have any division functions. If you need to perform divisions on these types, you need to convert it to its underlying type, do the division and convert it back. It would make sense to provide these methods directly on the types.

Motivating examples or use cases

I recently needed this when calculating the number of sheets needed for printing a document using duplex printing.
As a document can never have 0 pages, I represent the page count as a NonZero<u32>. The number of sheets required can then be calculated with (assuming that div_ceil exists on NonZero<u32>):

fn duplex_sheets(pages: NonZero) -> NonZero { // SAFETY: 2 is not zero const TWO: NonZero = unsafe { NonZero::::new_unchecked(2) }; pages.div_ceil(TWO) }

Solution sketch

NonZero<unsigned> should implement div_ceil as it would be panic-free and could never produce a zero:

impl NonZero { // similarly for u16, u32, u64, u128 & usize pub const fn div_ceil(self, other: Self) -> Self; }

I think it would be weird to just add just `div_ceil` without also adding a checked version of "regular" division. The signed `NonZero` types should probably also have the checked "regular" division function.

So in conclusion I think the following functions should be added to core:

impl NonZero { // similarly for u16, u32, u64, u128 & usize pub const fn checked_div(self, other: Self) -> Option; pub const fn div_ceil(self, other: Self) -> Self; }

impl NonZero { // similarly for i16, i32, i64, i128 & isize pub const fn checked_div(self, other: Self) -> Option; }

Alternatives

Alternatively users can define these themselves using an extension trait or using a separate function.

For example:

use std::num::NonZero;

pub(crate) trait NonZeroUnsignedExt { fn div_ceil(self, divisor: Self) -> Self; }

impl NonZeroUnsignedExt for NonZero { fn div_ceil(self, divisor: Self) -> Self { let v = self.get().div_ceil(divisor.get()); // SAFETY: v can never be zero unsafe { Self::new_unchecked(v) } } }

The user will either need to use unsafe or unwrap to create the result, which they could avoid if div_ceil was implemented in core.

What happens now?

This issue contains an API change proposal (or ACP) and is part of the libs-api team feature lifecycle. Once this issue is filed, the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.

Possible responses

The libs team may respond in various different ways. First, the team will consider the problem (this doesn't require any concrete solution or alternatives to have been proposed):

Second, if there's a concrete solution: