1// Copyright 2025 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
45//! Types and utilities for dealing with numerical values.
67use core::num::{NonZeroIsize, NonZeroUsize};
89/// An `isize` that is strictly positive (greater than 0).
10///
11/// `PositiveIsize` differs from [`NonZeroUsize`] in that it is guaranteed to
12/// fit in an `isize` (i.e. the maximum value is `isize::MAX` as opposed to
13/// `usize::MAX`).
14#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, Ord, PartialOrd)]
15pub struct PositiveIsize(isize);
1617impl PositiveIsize {
18/// Creates a new `PositiveIsize` from an `isize` value.
19 ///
20 /// Returns `None` if `value` is less than or equal to zero.
21pub const fn new(value: isize) -> Option<Self> {
22if value > 0 {
23Some(Self(value))
24 } else {
25None
26}
27 }
2829/// Creates a new `PositiveIsize` from a `usize` value.
30 ///
31 /// Returns `None` if `value` is zero or larger than `isize::MAX`.
32pub const fn new_unsigned(value: usize) -> Option<Self> {
33if value == 0 || value > (isize::MAX as usize) {
34None
35} else {
36Some(Self(value as isize))
37 }
38 }
3940/// Returns the `isize` value within this `PositiveIsize`.
41pub const fn get(self) -> isize {
42let Self(v) = self;
43 v
44 }
45}
4647impl From<PositiveIsize> for isize {
48fn from(PositiveIsize(value): PositiveIsize) -> Self {
49 value
50 }
51}
5253impl From<PositiveIsize> for usize {
54fn from(PositiveIsize(value): PositiveIsize) -> Self {
55// Conversion is guaranteed to be infallible because `PositiveIsize`
56 // creation guarantees: a positive `isize` always fits within a `usize`.
57value as usize
58 }
59}
6061impl From<PositiveIsize> for NonZeroIsize {
62fn from(PositiveIsize(value): PositiveIsize) -> Self {
63// SAFETY: value is guaranteed to be nonzero.
64unsafe { NonZeroIsize::new_unchecked(value) }
65 }
66}
6768impl From<PositiveIsize> for NonZeroUsize {
69fn from(PositiveIsize(value): PositiveIsize) -> Self {
70// value is guaranteed to be positive.
71let value = value as usize;
72// SAFETY: value is guaranteed to be nonzero.
73unsafe { NonZeroUsize::new_unchecked(value) }
74 }
75}
7677#[cfg(test)]
78mod tests {
79use super::*;
8081#[test]
82fn new_positive_isize() {
83assert_eq!(PositiveIsize::new(0), None);
84assert_eq!(PositiveIsize::new(-1), None);
85assert_eq!(PositiveIsize::new(1), Some(PositiveIsize(1)));
86assert_eq!(PositiveIsize::new(isize::MIN), None);
87assert_eq!(PositiveIsize::new(isize::MAX), Some(PositiveIsize(isize::MAX)));
88 }
8990#[test]
91fn new_unsigned_positive_isize() {
92assert_eq!(PositiveIsize::new_unsigned(0), None);
93assert_eq!(PositiveIsize::new_unsigned(usize::MAX), None);
94assert_eq!(PositiveIsize::new_unsigned(1), Some(PositiveIsize(1)));
95let max = usize::try_from(isize::MAX).unwrap();
96assert_eq!(PositiveIsize::new_unsigned(max), Some(PositiveIsize(isize::MAX)));
97assert_eq!(PositiveIsize::new_unsigned(max + 1), None);
98 }
99}