Skip to main content

bounded_integer/
lib.rs

1//! This crate provides two types of bounded integer.
2//!
3//! # Macro-generated bounded integers
4//!
5//! The [`bounded_integer!`] macro allows you to define your own bounded integer type, given a
6//! specific (inclusive) range it inhabits. For example:
7//!
8//! ```rust
9#![cfg_attr(not(feature = "macro"), doc = "# #[cfg(any())] {")]
10#![cfg_attr(feature = "step_trait", doc = "# #![feature(step_trait)]")]
11//! # use bounded_integer::bounded_integer;
12//! bounded_integer! {
13//!     struct MyInteger(0, 7);
14//! }
15//! let num = MyInteger::new(5).unwrap();
16//! assert_eq!(num, 5);
17#![cfg_attr(not(feature = "macro"), doc = "# }")]
18//! ```
19//!
20//! This macro supports both `struct`s and `enum`s. See the [`examples`] module for the
21//! documentation of generated types.
22//!
23//! # Const generics-based bounded integers
24//!
25//! You can also create ad-hoc bounded integers via types in this library that use const generics,
26//! for example:
27//!
28//! ```rust
29#![cfg_attr(feature = "step_trait", doc = "# #![feature(step_trait)]")]
30//! # use bounded_integer::BoundedU8;
31//! let num = <BoundedU8<0, 7>>::new(5).unwrap();
32//! assert_eq!(num, 5);
33//! ```
34//!
35//! These integers are shorter to use as they don't require a type declaration or explicit name.
36//! However due to the limits of const generics, they may not implement some traits –
37//! namely [`Default`], bytemuck’s [`Zeroable`] and zerocopy’s [`FromZeros`].
38//! Also, unlike their macro counterparts they will not be subject to niche layout optimizations.
39//!
40//! # `no_std`
41//!
42//! All the integers in this crate depend only on libcore and so work in `#![no_std]` environments.
43//!
44//! # Crate Features
45//!
46//! By default, no crate features are enabled.
47//! - `std`: Interopate with `std` — implies `alloc`. Has no effect currently.
48//! - `alloc`: Interopate with `alloc`. Has no effect currently.
49//! - `macro`: Enable the [`bounded_integer!`] macro.
50//! - `arbitrary1`: Implement [`Arbitrary`] for the bounded integers. This is useful when using
51//!   bounded integers as fuzzing inputs.
52//! - `bytemuck1`: Implement [`Contiguous`] and [`NoUninit`] for all bounded integers,
53//!   and [`Zeroable`] for macro-generated bounded integers that support it.
54//! - `num-traits02`: Implement [`Bounded`], [`AsPrimitive`], [`FromPrimitive`], [`NumCast`],
55//!   [`ToPrimitive`], [`CheckedAdd`], [`CheckedDiv`], [`CheckedMul`], [`CheckedNeg`],
56//!   [`CheckedRem`], [`CheckedSub`], [`MulAdd`], [`SaturatingAdd`], [`SaturatingMul`] and
57//!   [`SaturatingSub`] for all bounded integers.
58//! - `serde1`: Implement [`Serialize`] and [`Deserialize`] for the bounded integers, making sure all
59//!   values will never be out of bounds.
60//! - `schemars1`: Implement [`JsonSchema`] for the bounded integers, describing them as their
61//!   underlying primitive constrained to the type’s range via `minimum` and `maximum`. Bounds of
62//!   `i128`/`u128`-backed integers that fall outside the `i64`/`u64` range are omitted unless
63//!   `serde_json`’s `arbitrary_precision` feature is enabled (which has a significant runtime cost).
64//! - `zerocopy`: Implement [`IntoBytes`] and [`Immutable`] for all bounded integers,
65//!   [`Unaligned`] for ones backed by `u8` or `i8`,
66//!   and [`FromZeros`] for suitable macro-generated ones.
67//! - `step_trait`: Implement the [`Step`] trait which allows the bounded integers to be easily used
68//!   in ranges. This will require you to use nightly and place `#![feature(step_trait)]` in your
69//!   crate root if you use the macro.
70//!
71//! [`bounded_integer!`]: https://docs.rs/bounded-integer/*/bounded_integer/macro.bounded_integer.html
72//! [`examples`]: https://docs.rs/bounded-integer/*/bounded_integer/examples/
73//! [`Arbitrary`]: https://docs.rs/arbitrary/1/arbitrary/trait.Arbitrary.html
74//! [`Contiguous`]: https://docs.rs/bytemuck/1/bytemuck/trait.Contiguous.html
75//! [`NoUninit`]: https://docs.rs/bytemuck/1/bytemuck/trait.NoUninit.html
76//! [`Zeroable`]: https://docs.rs/bytemuck/1/bytemuck/trait.Zeroable.html
77//! [`Bounded`]: https://docs.rs/num-traits/0.2/num_traits/bounds/trait.Bounded.html
78//! [`AsPrimitive`]: https://docs.rs/num-traits/0.2/num_traits/cast/trait.AsPrimitive.html
79//! [`FromPrimitive`]: https://docs.rs/num-traits/0.2/num_traits/cast/trait.FromPrimitive.html
80//! [`NumCast`]: https://docs.rs/num-traits/0.2/num_traits/cast/trait.NumCast.html
81//! [`ToPrimitive`]: https://docs.rs/num-traits/0.2/num_traits/cast/trait.ToPrimitive.html
82//! [`CheckedAdd`]: https://docs.rs/num-traits/0.2/num_traits/ops/checked/trait.CheckedAdd.html
83//! [`CheckedDiv`]: https://docs.rs/num-traits/0.2/num_traits/ops/checked/trait.CheckedDiv.html
84//! [`CheckedMul`]: https://docs.rs/num-traits/0.2/num_traits/ops/checked/trait.CheckedMul.html
85//! [`CheckedNeg`]: https://docs.rs/num-traits/0.2/num_traits/ops/checked/trait.CheckedNeg.html
86//! [`CheckedRem`]: https://docs.rs/num-traits/0.2/num_traits/ops/checked/trait.CheckedRem.html
87//! [`CheckedSub`]: https://docs.rs/num-traits/0.2/num_traits/ops/checked/trait.CheckedSub.html
88//! [`MulAdd`]: https://docs.rs/num-traits/0.2/num_traits/ops/mul_add/trait.MulAdd.html
89//! [`SaturatingAdd`]: https://docs.rs/num-traits/0.2/num_traits/ops/saturating/trait.SaturatingAdd.html
90//! [`SaturatingMul`]: https://docs.rs/num-traits/0.2/num_traits/ops/saturating/trait.SaturatingMul.html
91//! [`SaturatingSub`]: https://docs.rs/num-traits/0.2/num_traits/ops/saturating/trait.SaturatingSub.html
92//! [`Serialize`]: https://docs.rs/serde/1/serde/trait.Serialize.html
93//! [`Deserialize`]: https://docs.rs/serde/1/serde/trait.Deserialize.html
94//! [`JsonSchema`]: https://docs.rs/schemars/1/schemars/trait.JsonSchema.html
95//! [`IntoBytes`]: https://docs.rs/zerocopy/0.8/zerocopy/trait.IntoBytes.html
96//! [`FromZeros`]: https://docs.rs/zerocopy/0.8/zerocopy/trait.FromZeros.html
97//! [`Immutable`]: https://docs.rs/zerocopy/0.8/zerocopy/trait.Immutable.html
98//! [`Unaligned`]: https://docs.rs/zerocopy/0.8/zerocopy/trait.Unaligned.html
99//! [`Step`]: https://doc.rust-lang.org/nightly/core/iter/trait.Step.html
100//! [`Error`]: https://doc.rust-lang.org/stable/std/error/trait.Error.html
101//! [`ParseError`]: https://docs.rs/bounded-integer/*/bounded_integer/struct.ParseError.html
102#![warn(clippy::pedantic, rust_2018_idioms, unused_qualifications)]
103#![allow(clippy::items_after_statements, clippy::missing_errors_doc)]
104#![cfg_attr(feature = "step_trait", feature(step_trait))]
105#![cfg_attr(feature = "__doc", feature(doc_cfg))]
106#![no_std]
107
108#[cfg(feature = "std")]
109extern crate std;
110
111#[cfg(feature = "alloc")]
112#[cfg(test)]
113extern crate alloc;
114
115mod types;
116pub use types::*;
117
118#[cfg(feature = "macro")]
119mod r#macro;
120
121mod parse;
122pub use parse::{ParseError, ParseErrorKind};
123
124mod prim_int;
125pub use prim_int::TryFromError;
126
127// Not public API.
128#[doc(hidden)]
129pub mod __private {
130    #[cfg(feature = "alloc")]
131    pub extern crate alloc;
132
133    #[cfg(feature = "arbitrary1")]
134    pub use ::arbitrary1;
135
136    #[cfg(feature = "bytemuck1")]
137    pub use ::bytemuck1;
138
139    #[cfg(feature = "num-traits02")]
140    pub use ::num_traits02;
141
142    #[cfg(feature = "schemars1")]
143    pub use ::{schemars1, serde_json1};
144
145    #[cfg(feature = "serde1")]
146    pub use ::serde1;
147
148    #[cfg(feature = "zerocopy")]
149    pub use ::zerocopy;
150
151    #[cfg(feature = "macro")]
152    pub use bounded_integer_macro::bounded_integer as proc_macro;
153
154    // Helper to allow type-driven dispatch in `const fn`.
155    pub struct Dispatch<T>(T, core::convert::Infallible);
156
157    pub trait NewWrapping<T> {
158        #[doc(hidden)]
159        fn new_wrapping(n: T) -> Self;
160    }
161
162    pub use crate::parse::{error_above_max, error_below_min};
163    pub use crate::prim_int::{Signed, Unsigned, Wide, try_from_error};
164
165    feature_flags! { $
166        __cfg_arbitrary1 "arbitrary1",
167        __cfg_bytemuck1 "bytemuck1",
168        __cfg_num_traits02 "num-traits02",
169        __cfg_schemars1 "schemars1",
170        __cfg_serde1 "serde1",
171        __cfg_step_trait "step_trait",
172        __cfg_zerocopy "zerocopy",
173    }
174    macro_rules! feature_flags {
175        ($d:tt $($cfg:ident $flag:literal,)*) => { $(
176            #[macro_export]
177            #[cfg(feature = $flag)]
178            #[doc(hidden)]
179            #[cfg(not(feature = "__doc"))]
180            macro_rules! $cfg {
181                ($d ($tt:tt)*) => { $d ($tt)* };
182            }
183            // If the `__doc` feature flag is enabled, we are building for the current crate, and
184            // thus we forward the `cfg` so that `doc_cfg` sees it.
185            #[macro_export]
186            #[cfg(feature = $flag)]
187            #[doc(hidden)]
188            #[cfg(feature = "__doc")]
189            macro_rules! $cfg {
190                ($d ($item:item)*) => { $d (#[cfg(feature = $flag)] $item)* };
191            }
192            #[macro_export]
193            #[cfg(not(feature = $flag))]
194            #[doc(hidden)]
195            macro_rules! $cfg {
196                ($d ($tt:tt)*) => {};
197            }
198            pub use $cfg;
199        )* };
200    }
201    use feature_flags;
202}
203
204#[cfg(feature = "__doc")]
205pub mod examples;
206
207#[test]
208#[cfg(feature = "macro")]
209// Don’t test on Nightly because the output is different to stable.
210#[cfg(not(feature = "__doc"))]
211fn ui() {
212    let t = trybuild::TestCases::new();
213    t.pass("tests/force_build.rs");
214    t.compile_fail("ui/*.rs");
215}
216
217mod unsafe_api;