1use num::Signed;
20use num::traits::bounds::UpperBounded;
21#[cfg(feature = "proptest")]
22use proptest::arbitrary::Arbitrary;
23#[cfg(feature = "proptest")]
24use proptest::strategy::{BoxedStrategy, Strategy};
25use serde::{Deserialize, Serialize};
26use std::error::Error;
27use std::fmt;
28use std::ops::Deref;
29#[cfg(feature = "proptest")]
30use std::ops::Range;
31
32#[derive(
34 Debug,
35 Clone,
36 Copy,
37 Serialize,
38 Deserialize,
39 Eq,
40 PartialEq,
41 Hash,
42 Ord,
43 PartialOrd
44)]
45#[repr(transparent)]
46#[serde(transparent)]
47pub struct NonNeg<T>(T)
48where
49 T: Signed + fmt::Display;
50
51impl<T> NonNeg<T>
52where
53 T: Signed + fmt::Display,
54{
55 pub fn min() -> NonNeg<T> {
57 NonNeg(T::zero())
58 }
59
60 pub fn max() -> NonNeg<T>
62 where
63 T: UpperBounded,
64 {
65 NonNeg(T::max_value())
66 }
67
68 pub fn try_from(n: T) -> Result<NonNeg<T>, NonNegError> {
72 match n.is_negative() {
73 false => Ok(NonNeg(n)),
74 true => Err(NonNegError),
75 }
76 }
77}
78
79impl<T> fmt::Display for NonNeg<T>
80where
81 T: Signed + fmt::Display,
82{
83 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
84 self.0.fmt(f)
85 }
86}
87
88impl<T> Deref for NonNeg<T>
89where
90 T: Signed + fmt::Display,
91{
92 type Target = T;
93
94 fn deref(&self) -> &T {
95 &self.0
96 }
97}
98
99impl From<NonNeg<i64>> for u64 {
100 fn from(n: NonNeg<i64>) -> u64 {
101 u64::try_from(*n).expect("non-negative")
102 }
103}
104
105#[cfg(target_pointer_width = "64")]
106impl crate::cast::CastFrom<NonNeg<i64>> for usize {
107 #[allow(clippy::as_conversions)]
108 fn cast_from(from: NonNeg<i64>) -> usize {
109 usize::cast_from(u64::from(from))
110 }
111}
112
113#[cfg(feature = "proptest")]
114impl<T> Arbitrary for NonNeg<T>
115where
116 T: Signed + UpperBounded + fmt::Display + fmt::Debug + Copy + 'static,
117 Range<T>: Strategy<Value = T>,
118{
119 type Strategy = BoxedStrategy<Self>;
120 type Parameters = ();
121
122 fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
123 (*Self::min()..*Self::max()).prop_map(NonNeg).boxed()
124 }
125}
126
127#[derive(Debug, Clone)]
130pub struct NonNegError;
131
132impl fmt::Display for NonNegError {
133 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
134 f.write_str("cannot construct NonNeg from negative number")
135 }
136}
137
138impl Error for NonNegError {}