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(Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq, Hash, Ord, PartialOrd)]
34#[repr(transparent)]
35#[serde(transparent)]
36pub struct NonNeg<T>(T)
37where
38 T: Signed + fmt::Display;
39
40impl<T> NonNeg<T>
41where
42 T: Signed + fmt::Display,
43{
44 pub fn min() -> NonNeg<T> {
46 NonNeg(T::zero())
47 }
48
49 pub fn max() -> NonNeg<T>
51 where
52 T: UpperBounded,
53 {
54 NonNeg(T::max_value())
55 }
56
57 pub fn try_from(n: T) -> Result<NonNeg<T>, NonNegError> {
61 match n.is_negative() {
62 false => Ok(NonNeg(n)),
63 true => Err(NonNegError),
64 }
65 }
66}
67
68impl<T> fmt::Display for NonNeg<T>
69where
70 T: Signed + fmt::Display,
71{
72 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73 self.0.fmt(f)
74 }
75}
76
77impl<T> Deref for NonNeg<T>
78where
79 T: Signed + fmt::Display,
80{
81 type Target = T;
82
83 fn deref(&self) -> &T {
84 &self.0
85 }
86}
87
88impl From<NonNeg<i64>> for u64 {
89 fn from(n: NonNeg<i64>) -> u64 {
90 u64::try_from(*n).expect("non-negative")
91 }
92}
93
94#[cfg(target_pointer_width = "64")]
95impl crate::cast::CastFrom<NonNeg<i64>> for usize {
96 #[allow(clippy::as_conversions)]
97 fn cast_from(from: NonNeg<i64>) -> usize {
98 usize::cast_from(u64::from(from))
99 }
100}
101
102#[cfg(feature = "proptest")]
103impl<T> Arbitrary for NonNeg<T>
104where
105 T: Signed + UpperBounded + fmt::Display + fmt::Debug + Copy + 'static,
106 Range<T>: Strategy<Value = T>,
107{
108 type Strategy = BoxedStrategy<Self>;
109 type Parameters = ();
110
111 fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
112 (*Self::min()..*Self::max()).prop_map(NonNeg).boxed()
113 }
114}
115
116#[derive(Debug, Clone)]
119pub struct NonNegError;
120
121impl fmt::Display for NonNegError {
122 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
123 f.write_str("cannot construct NonNeg from negative number")
124 }
125}
126
127impl Error for NonNegError {}