1#![allow(clippy::incompatible_msrv)]
3
4pub trait Integer: private::Sealed {}
8
9mod private {
10 pub trait Sealed {
11 fn copy(&self) -> Self;
12 fn eq(self, other: Self) -> bool;
13 fn lt(self, other: Self) -> bool;
14 fn checked_ilog(self, base: Self) -> Option<u32>;
15 fn ilog(self, base: u32) -> u32;
16 fn checked_ilog10(self) -> Option<u32>;
17 fn ilog10(self) -> u32;
18 fn invpow(self, base: u32, exp: u32) -> Self;
20 }
21}
22
23macro_rules! sealed_common {
24 () => {
25 fn copy(&self) -> Self {
26 *self
27 }
28
29 fn eq(self, other: Self) -> bool {
30 self == other
31 }
32
33 fn lt(self, other: Self) -> bool {
34 self < other
35 }
36
37 fn checked_ilog(mut self, base: Self) -> Option<u32> {
38 if base <= 1 {
42 assert!(base > 0);
43 return Some(0);
44 }
45 let mut x = 0;
46 while self >= base {
47 self /= base;
48 x += 1;
49 }
50 Some(x)
51 }
52
53 #[allow(unstable_name_collisions)]
56 fn ilog(self, base: u32) -> u32 {
57 if let Some(x) = self.checked_ilog(base as _) {
58 x
59 } else {
60 0
61 }
62 }
63
64 #[allow(unstable_name_collisions)]
65 fn ilog10(self) -> u32 {
66 if let Some(x) = self.checked_ilog10() {
67 x
68 } else {
69 0
70 }
71 }
72
73 fn invpow(mut self, base: u32, mut exp: u32) -> Self {
74 if exp == 0 {
80 return self;
81 }
82 let mut base = base as Self;
85
86 while exp > 1 {
87 if (exp & 1) == 1 {
88 self /= base;
89 }
90 exp /= 2;
91 base = base * base;
92 }
93
94 self / base
95 }
96 };
97}
98
99impl private::Sealed for u32 {
103 sealed_common!();
104
105 #[allow(unstable_name_collisions)]
106 fn checked_ilog10(mut self) -> Option<u32> {
107 let x = if self >= 100_000 {
108 self /= 100_000;
109 5
110 } else {
111 0
112 };
113
114 assert!((!0_u32) / 100_000 <= (!0_u16) as u32);
116 debug_assert!(self <= (!0_u16) as u32); Some((self as u16).ilog(10) + x)
119 }
120}
121
122impl private::Sealed for u64 {
123 sealed_common!();
124
125 #[allow(unstable_name_collisions)]
126 fn checked_ilog10(mut self) -> Option<u32> {
127 let x = if self >= 10_000_000_000 {
128 self /= 10_000_000_000;
129 10
130 } else {
131 0
132 };
133 assert!((!0_u64) / 10_000_000_000 <= (!0_u32) as u64);
134 debug_assert!(self <= (!0_u32) as u64);
135 Some((self as u32).ilog(10) + x)
136 }
137}
138
139impl private::Sealed for u128 {
140 sealed_common!();
141
142 #[allow(unstable_name_collisions)]
143 fn checked_ilog10(mut self) -> Option<u32> {
144 if self >= 100_000_000_000_000_000_000_000_000_000_000 {
145 self /= 100_000_000_000_000_000_000_000_000_000_000;
146 assert!((!0_u128) / 100_000_000_000_000_000_000_000_000_000_000 <= (!0_u32) as u128);
147 debug_assert!(self <= (!0_u32) as u128);
148 return Some((self as u32).ilog(10) + 32);
149 }
150 let x = if self >= 10_000_000_000_000_000 {
151 self /= 10_000_000_000_000_000;
152 16
153 } else {
154 0
155 };
156 assert!(
157 (100_000_000_000_000_000_000_000_000_000_000 - 1) / 10_000_000_000_000_000
158 <= (!0_u64) as u128
159 );
160 debug_assert!(self <= (!0_u64) as u128);
161 Some((self as u64).ilog(10) + x)
162 }
163}
164
165macro_rules! generic_ilog10 {
166 ($($ty:ty)*) => {$(
167 impl private::Sealed for $ty {
168 sealed_common!();
169
170 #[allow(unstable_name_collisions)]
171 fn checked_ilog10(self) -> Option<u32> {
172 self.checked_ilog(10)
173 }
174 }
175 )*};
176}
177
178generic_ilog10! { u8 u16 }
179
180#[cfg(target_pointer_width = "64")]
181impl private::Sealed for usize {
182 sealed_common!();
183 #[allow(unstable_name_collisions)]
184 fn checked_ilog10(self) -> Option<u32> {
185 (self as u64).checked_ilog10()
186 }
187}
188
189#[cfg(target_pointer_width = "32")]
190impl private::Sealed for usize {
191 sealed_common!();
192 #[allow(unstable_name_collisions)]
193 fn checked_ilog10(self) -> Option<u32> {
194 (self as u32).checked_ilog10()
195 }
196}
197
198#[cfg(not(any(target_pointer_width = "64", target_pointer_width = "32")))]
199generic_ilog10! { usize }
200
201impl Integer for u8 {}
202impl Integer for u16 {}
203impl Integer for u32 {}
204impl Integer for u64 {}
205impl Integer for u128 {}
206impl Integer for usize {}