Skip to content

Commit c702e8f

Browse files
committed
num_traits::{Zero, One}
1 parent 8737093 commit c702e8f

12 files changed

Lines changed: 206 additions & 115 deletions

macro/src/lib.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -187,14 +187,21 @@ pub fn bounded_integer(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
187187
[t] => panic!("named ({t})"),
188188
}
189189

190-
let zeroable = min_val
190+
let zero = min_val
191191
.zip(max_val)
192192
.map(|(min, max)| (min..=max).contains(&Int::new(true, 0)));
193-
if zeroable == Some(true) && zerocopy {
193+
let one = min_val
194+
.zip(max_val)
195+
.map(|(min, max)| (min..=max).contains(&Int::new(true, 1)));
196+
if zero == Some(true) && zerocopy {
194197
attrs.extend(quote!(#[derive(#crate_path::__private::zerocopy::FromZeros)]));
195198
}
196-
let zeroable_token = match zeroable {
197-
Some(true) => quote!(zeroable,),
199+
let zero_token = match zero {
200+
Some(true) => quote!(zero,),
201+
Some(false) | None => quote!(),
202+
};
203+
let one_token = match one {
204+
Some(true) => quote!(one,),
198205
Some(false) | None => quote!(),
199206
};
200207

@@ -224,7 +231,7 @@ pub fn bounded_integer(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
224231

225232
let item = match variants {
226233
Some(variants) => quote!({ #variants }),
227-
None if zeroable == Some(false) => quote!((::core::num::NonZero<#repr>);),
234+
None if zero == Some(false) => quote!((::core::num::NonZero<#repr>);),
228235
None => quote!((#repr);),
229236
};
230237

@@ -242,7 +249,8 @@ pub fn bounded_integer(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
242249
unsafe repr: #repr,
243250
min: #min,
244251
max: #max,
245-
#zeroable_token
252+
#zero_token
253+
#one_token
246254
}
247255
}
248256
#vis use #module_name::#name;

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@
103103

104104
// TODO: propagate warning attributes to all items in the macro
105105
// TODO: TryFrom and TryInto
106+
// TODO: Test the `where` clause
106107

107108
#[cfg(feature = "std")]
108109
extern crate std;

src/macro.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,9 +317,13 @@ mod tests {
317317

318318
#[test]
319319
fn zeroable() {
320-
#[cfg(all(feature = "bytemuck1", feature = "zerocopy"))]
321-
fn assert_zeroable<T: Default + bytemuck1::Zeroable + zerocopy::FromZeros>() {}
322-
#[cfg(not(all(feature = "bytemuck1", feature = "zerocopy")))]
320+
#[cfg(all(feature = "bytemuck1", feature = "zerocopy", feature = "num-traits02"))]
321+
fn assert_zeroable<T>()
322+
where
323+
T: Default + bytemuck1::Zeroable + zerocopy::FromZeros + num_traits02::Zero,
324+
{
325+
}
326+
#[cfg(not(all(feature = "bytemuck1", feature = "zerocopy", feature = "num-traits02")))]
323327
fn assert_zeroable<T: Default>() {}
324328
#[expect(unused)]
325329
trait NotZeroable<const N: usize> {}
@@ -328,13 +332,17 @@ mod tests {
328332
impl<T: bytemuck1::Zeroable> NotZeroable<1> for T {}
329333
#[cfg(feature = "zerocopy")]
330334
impl<T: zerocopy::FromZeros> NotZeroable<2> for T {}
335+
#[cfg(feature = "num-traits02")]
336+
impl<T: num_traits02::Zero> NotZeroable<3> for T {}
331337
macro_rules! not_zeroable {
332338
($t:ty) => {
333339
impl NotZeroable<0> for $t {}
334340
#[cfg(feature = "bytemuck1")]
335341
impl NotZeroable<1> for $t {}
336342
#[cfg(feature = "zerocopy")]
337343
impl NotZeroable<2> for $t {}
344+
#[cfg(feature = "num-traits02")]
345+
impl NotZeroable<3> for $t {}
338346
};
339347
}
340348

@@ -357,6 +365,14 @@ mod tests {
357365
assert_ne!(size_of::<Option<E>>(), size_of::<E>());
358366
}
359367

368+
#[test]
369+
#[cfg(feature = "num-traits02")]
370+
fn one() {
371+
fn assert_one<T: num_traits02::One>() {}
372+
bounded_integer!(struct A(1, 1););
373+
assert_one::<A>();
374+
}
375+
360376
#[test]
361377
#[cfg(feature = "zerocopy")]
362378
fn unaligned() {

src/unsafe_api.rs

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
/// Takes in a `ty` and a `repr`. `ty` must be a type whose layout is identical to `repr`.
88
///
99
/// `min` and `max` are const expressions giving the bounds of the type (inclusive).
10-
/// If `zeroable` is provided, various traits like [`Default`] will be implemented.
10+
/// If `zero` is provided, various traits like [`Default`] will be implemented;
11+
/// if `one` is provided, `num_traits::One` will be implemented.
1112
///
1213
/// # Safety
1314
///
@@ -25,7 +26,8 @@
2526
/// unsafe repr: u8,
2627
/// min: 0,
2728
/// max: 37,
28-
/// zeroable,
29+
/// zero,
30+
/// one,
2931
/// }
3032
///
3133
/// assert_eq!(MyInteger::new(0).unwrap(), 0);
@@ -52,15 +54,17 @@ macro_rules! unsafe_api {
5254
unsafe repr: $repr:tt,
5355
min: $min:expr,
5456
max: $max:expr,
55-
$(zeroable $([$($_:tt)* $zeroable:tt])?,)?
57+
$(zero $([$($_:tt)* $zero:tt])?,)?
58+
$(one $([$($__:tt)* $one:tt])?,)?
5659
) => {
5760
$crate::__unsafe_api_internal! {
5861
@repr $repr,
5962
[$($($generics)*)?] $ty where { $($($where)*)? },
6063
([$($($generics)*)?] where $($($where)*)?),
6164
min: $min,
6265
max: $max,
63-
$(zeroable, $($zeroable)?)?
66+
$(zero, $($zero)?)?
67+
$(one, $($one)?)?
6468
}
6569
};
6670
}
@@ -80,7 +84,8 @@ macro_rules! __unsafe_api_internal {
8084
$generics_single_token:tt,
8185
min: $min:expr,
8286
max: $max:expr,
83-
$(zeroable $([$zeroable:tt])?,)?
87+
$(zero $([$zero:tt])?,)?
88+
$(one $([$one:tt])?,)?
8489
) => { const _: () = {
8590
// The presence of these imports is somewhat unhygienic: it means users cannot name their
8691
// type any of these things. This can always be changed if the need arises.
@@ -700,12 +705,23 @@ macro_rules! __unsafe_api_internal {
700705

701706
// === Default ===
702707

703-
#[cfg(not(all($($($zeroable)? false)?)))]
708+
#[cfg(not(all($($($zero)? false)?)))]
704709
#[automatically_derived]
705710
impl<$($generics)*> Default for $ty where $($where)* {
706711
fn default() -> Self {
707712
const {
708-
Self::new(0).expect("used `zeroable` on a type whose range does not include zero")
713+
Self::new(0).expect("used `zero` on a type whose range does not include zero")
714+
}
715+
}
716+
}
717+
718+
// Use a function to force post-mono errors even if `num-traits02` is disabled.
719+
#[cfg(not(all($($($one)? false)?)))]
720+
impl<$($generics)*> $ty where $($where)* {
721+
#[allow(unused)]
722+
fn one() -> Self {
723+
const {
724+
Self::new(1).expect("used `one` on a type whose range does not include one")
709725
}
710726
}
711727
}
@@ -1013,7 +1029,7 @@ macro_rules! __unsafe_api_internal {
10131029
#[automatically_derived]
10141030
unsafe impl<$($generics)*> bytemuck1::NoUninit for $ty {}
10151031

1016-
#[cfg(not(all($($(if $zeroable)? false)?)))]
1032+
#[cfg(not(all($($(if $zero)? false)?)))]
10171033
#[automatically_derived]
10181034
unsafe impl<$($generics)*> bytemuck1::Zeroable for $ty {}
10191035
}
@@ -1241,7 +1257,24 @@ macro_rules! __unsafe_api_internal {
12411257
}
12421258
}
12431259

1244-
// TODO: implement `Zero`/`One`?
1260+
#[cfg(not(all($($($zero)? false)?)))]
1261+
#[automatically_derived]
1262+
impl<$($generics)*> num_traits02::Zero for $ty {
1263+
fn zero() -> Self {
1264+
Self::default()
1265+
}
1266+
fn is_zero(&self) -> bool {
1267+
self.get() == 0
1268+
}
1269+
}
1270+
1271+
#[cfg(not(all($($($one)? false)?)))]
1272+
#[automatically_derived]
1273+
impl<$($generics)*> num_traits02::One for $ty {
1274+
fn one() -> Self {
1275+
Self::one()
1276+
}
1277+
}
12451278
}
12461279

12471280
// === Serde ===
@@ -1530,7 +1563,7 @@ mod tests {
15301563
},
15311564
min: -5,
15321565
max: 5,
1533-
zeroable,
1566+
zero,
15341567
}
15351568
}
15361569
}

ui/bad_range.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#![cfg_attr(feature = "step_trait", feature(step_trait))]
21
fn main() {
32
#![expect(unused)]
43
let _ = <bounded_integer::BoundedUsize<5, 4>>::MIN;

ui/bad_range.stderr

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,39 +13,39 @@ error[E0080]: evaluation panicked: range minimum should be less than maximum
1313
= note: this error originates in the macro `$crate::__unsafe_api_internal` which comes from the expansion of the macro `define_bounded_integers` (in Nightly builds, run with -Z macro-backtrace for more info)
1414

1515
note: erroneous constant encountered
16-
--> ui/bad_range.rs:4:13
16+
--> ui/bad_range.rs:3:13
1717
|
18-
4 | let _ = <bounded_integer::BoundedUsize<5, 4>>::MIN;
18+
3 | let _ = <bounded_integer::BoundedUsize<5, 4>>::MIN;
1919
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2020

2121
error[E0080]: evaluation panicked: range minimum should be less than maximum
22-
--> ui/bad_range.rs:5:5
22+
--> ui/bad_range.rs:4:5
2323
|
24-
5 | bounded_integer::bounded_integer!(struct X(5, 4););
24+
4 | bounded_integer::bounded_integer!(struct X(5, 4););
2525
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::__bounded_integer_private_X::_::<impl main::__bounded_integer_private_X::X>::MIN` failed here
2626
|
2727
= note: this error originates in the macro `$crate::__unsafe_api_internal` which comes from the expansion of the macro `bounded_integer::bounded_integer` (in Nightly builds, run with -Z macro-backtrace for more info)
2828

2929
note: erroneous constant encountered
30-
--> ui/bad_range.rs:5:5
30+
--> ui/bad_range.rs:4:5
3131
|
32-
5 | bounded_integer::bounded_integer!(struct X(5, 4););
32+
4 | bounded_integer::bounded_integer!(struct X(5, 4););
3333
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3434
|
3535
= note: this note originates in the macro `$crate::__unsafe_api_internal` which comes from the expansion of the macro `bounded_integer::bounded_integer` (in Nightly builds, run with -Z macro-backtrace for more info)
3636

3737
error[E0080]: evaluation panicked: range minimum should be less than maximum
38-
--> ui/bad_range.rs:5:5
38+
--> ui/bad_range.rs:4:5
3939
|
40-
5 | bounded_integer::bounded_integer!(struct X(5, 4););
40+
4 | bounded_integer::bounded_integer!(struct X(5, 4););
4141
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::__bounded_integer_private_X::_::<impl main::__bounded_integer_private_X::X>::MAX` failed here
4242
|
4343
= note: this error originates in the macro `$crate::__unsafe_api_internal` which comes from the expansion of the macro `bounded_integer::bounded_integer` (in Nightly builds, run with -Z macro-backtrace for more info)
4444

4545
note: erroneous constant encountered
46-
--> ui/bad_range.rs:5:5
46+
--> ui/bad_range.rs:4:5
4747
|
48-
5 | bounded_integer::bounded_integer!(struct X(5, 4););
48+
4 | bounded_integer::bounded_integer!(struct X(5, 4););
4949
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5050
|
5151
= note: this note originates in the macro `$crate::__unsafe_api_internal` which comes from the expansion of the macro `bounded_integer::bounded_integer` (in Nightly builds, run with -Z macro-backtrace for more info)

ui/const_new.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#![cfg_attr(feature = "step_trait", feature(step_trait))]
21
fn main() {
32
let _ = <bounded_integer::BoundedUsize<0, 5>>::const_new::<6>();
43
}

ui/const_new.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ note: erroneous constant encountered
2727
= note: this note originates in the macro `$crate::__unsafe_api_internal` which comes from the expansion of the macro `define_bounded_integers` (in Nightly builds, run with -Z macro-backtrace for more info)
2828

2929
note: the above error was encountered while instantiating `fn bounded_integer::types::_::<impl bounded_integer::BoundedUsize<0, 5>>::const_new::<6>`
30-
--> ui/const_new.rs:3:13
30+
--> ui/const_new.rs:2:13
3131
|
32-
3 | let _ = <bounded_integer::BoundedUsize<0, 5>>::const_new::<6>();
32+
2 | let _ = <bounded_integer::BoundedUsize<0, 5>>::const_new::<6>();
3333
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

ui/macro.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#![cfg_attr(feature = "step_trait", feature(step_trait))]
2-
31
use bounded_integer::bounded_integer;
42

53
bounded_integer! {

0 commit comments

Comments
 (0)