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`. Enables the following things:
48//! - An implementation of [`Error`] for [`ParseError`].
49//! - `alloc`: Interopate with `alloc`. Has no effect currently.
50//! - `macro`: Enable the [`bounded_integer!`] macro.
51//! - `arbitrary1`: Implement [`Arbitrary`] for the bounded integers. This is useful when using
52//! bounded integers as fuzzing inputs.
53//! - `bytemuck1`: Implement [`Contiguous`] and [`NoUninit`] for all bounded integers,
54//! and [`Zeroable`] for macro-generated bounded integers that support it.
55//! - `num-traits02`: Implement [`Bounded`], [`AsPrimitive`], [`FromPrimitive`], [`NumCast`],
56//! [`ToPrimitive`], [`CheckedAdd`], [`CheckedDiv`], [`CheckedMul`], [`CheckedNeg`],
57//! [`CheckedRem`], [`CheckedSub`], [`MulAdd`], [`SaturatingAdd`], [`SaturatingMul`] and
58//! [`SaturatingSub`] for all bounded integers.
59//! - `serde1`: Implement [`Serialize`] and [`Deserialize`] for the bounded integers, making sure all
60//! values will never be out of bounds.
61//! - `zerocopy`: Implement [`IntoBytes`] and [`Immutable`] for all bounded integers,
62//! [`Unaligned`] for ones backed by `u8` or `i8`,
63//! and [`FromZeros`] for suitable macro-generated ones.
64//! - `step_trait`: Implement the [`Step`] trait which allows the bounded integers to be easily used
65//! in ranges. This will require you to use nightly and place `#![feature(step_trait)]` in your
66//! crate root if you use the macro.
67//!
68//! [`bounded_integer!`]: https://docs.rs/bounded-integer/*/bounded_integer/macro.bounded_integer.html
69//! [`examples`]: https://docs.rs/bounded-integer/*/bounded_integer/examples/
70//! [`Arbitrary`]: https://docs.rs/arbitrary/1/arbitrary/trait.Arbitrary.html
71//! [`Contiguous`]: https://docs.rs/bytemuck/1/bytemuck/trait.Contiguous.html
72//! [`NoUninit`]: https://docs.rs/bytemuck/1/bytemuck/trait.NoUninit.html
73//! [`Zeroable`]: https://docs.rs/bytemuck/1/bytemuck/trait.Zeroable.html
74//! [`Bounded`]: https://docs.rs/num-traits/0.2/num_traits/bounds/trait.Bounded.html
75//! [`AsPrimitive`]: https://docs.rs/num-traits/0.2/num_traits/cast/trait.AsPrimitive.html
76//! [`FromPrimitive`]: https://docs.rs/num-traits/0.2/num_traits/cast/trait.FromPrimitive.html
77//! [`NumCast`]: https://docs.rs/num-traits/0.2/num_traits/cast/trait.NumCast.html
78//! [`ToPrimitive`]: https://docs.rs/num-traits/0.2/num_traits/cast/trait.ToPrimitive.html
79//! [`CheckedAdd`]: https://docs.rs/num-traits/0.2/num_traits/ops/checked/trait.CheckedAdd.html
80//! [`CheckedDiv`]: https://docs.rs/num-traits/0.2/num_traits/ops/checked/trait.CheckedDiv.html
81//! [`CheckedMul`]: https://docs.rs/num-traits/0.2/num_traits/ops/checked/trait.CheckedMul.html
82//! [`CheckedNeg`]: https://docs.rs/num-traits/0.2/num_traits/ops/checked/trait.CheckedNeg.html
83//! [`CheckedRem`]: https://docs.rs/num-traits/0.2/num_traits/ops/checked/trait.CheckedRem.html
84//! [`CheckedSub`]: https://docs.rs/num-traits/0.2/num_traits/ops/checked/trait.CheckedSub.html
85//! [`MulAdd`]: https://docs.rs/num-traits/0.2/num_traits/ops/mul_add/trait.MulAdd.html
86//! [`SaturatingAdd`]: https://docs.rs/num-traits/0.2/num_traits/ops/saturating/trait.SaturatingAdd.html
87//! [`SaturatingMul`]: https://docs.rs/num-traits/0.2/num_traits/ops/saturating/trait.SaturatingMul.html
88//! [`SaturatingSub`]: https://docs.rs/num-traits/0.2/num_traits/ops/saturating/trait.SaturatingSub.html
89//! [`Serialize`]: https://docs.rs/serde/1/serde/trait.Serialize.html
90//! [`Deserialize`]: https://docs.rs/serde/1/serde/trait.Deserialize.html
91//! [`IntoBytes`]: https://docs.rs/zerocopy/0.8/zerocopy/trait.IntoBytes.html
92//! [`FromZeros`]: https://docs.rs/zerocopy/0.8/zerocopy/trait.FromZeros.html
93//! [`Immutable`]: https://docs.rs/zerocopy/0.8/zerocopy/trait.Immutable.html
94//! [`Unaligned`]: https://docs.rs/zerocopy/0.8/zerocopy/trait.Unaligned.html
95//! [`Step`]: https://doc.rust-lang.org/nightly/core/iter/trait.Step.html
96//! [`Error`]: https://doc.rust-lang.org/stable/std/error/trait.Error.html
97//! [`ParseError`]: https://docs.rs/bounded-integer/*/bounded_integer/struct.ParseError.html
98#![warn(clippy::pedantic, rust_2018_idioms, unused_qualifications)]
99#![allow(clippy::items_after_statements, clippy::missing_errors_doc)]
100#![cfg_attr(feature = "step_trait", feature(step_trait))]
101#![cfg_attr(feature = "__doc", feature(doc_auto_cfg))]
102#![no_std]
103
104#[cfg(feature = "std")]
105extern crate std;
106
107#[cfg(feature = "alloc")]
108#[cfg(test)]
109extern crate alloc;
110
111mod types;
112pub use types::*;
113
114#[cfg(feature = "macro")]
115mod r#macro;
116
117mod parse;
118pub use parse::{ParseError, ParseErrorKind};
119
120mod prim_int;
121pub use prim_int::TryFromError;
122
123// Not public API.
124#[doc(hidden)]
125pub mod __private {
126 #[cfg(feature = "arbitrary1")]
127 pub use ::arbitrary1;
128
129 #[cfg(feature = "bytemuck1")]
130 pub use ::bytemuck1;
131
132 #[cfg(feature = "num-traits02")]
133 pub use ::num_traits02;
134
135 #[cfg(feature = "serde1")]
136 pub use ::serde1;
137
138 #[cfg(feature = "zerocopy")]
139 pub use ::zerocopy;
140
141 #[cfg(feature = "macro")]
142 pub use bounded_integer_macro::bounded_integer as proc_macro;
143
144 // Helper to allow type-driven dispatch in `const fn`.
145 pub struct Dispatch<T>(T, core::convert::Infallible);
146
147 pub trait NewWrapping<T> {
148 #[doc(hidden)]
149 fn new_wrapping(n: T) -> Self;
150 }
151
152 pub use crate::parse::{error_above_max, error_below_min};
153 pub use crate::prim_int::{Signed, Unsigned, Wide, try_from_error};
154
155 feature_flags! { $
156 __cfg_arbitrary1 "arbitrary1",
157 __cfg_bytemuck1 "bytemuck1",
158 __cfg_num_traits02 "num-traits02",
159 __cfg_serde1 "serde1",
160 __cfg_step_trait "step_trait",
161 __cfg_zerocopy "zerocopy",
162 }
163 macro_rules! feature_flags {
164 ($d:tt $($cfg:ident $flag:literal,)*) => { $(
165 #[macro_export]
166 #[cfg(feature = $flag)]
167 #[doc(hidden)]
168 #[cfg(not(feature = "__doc"))]
169 macro_rules! $cfg {
170 ($d ($tt:tt)*) => { $d ($tt)* };
171 }
172 // If the `__doc` feature flag is enabled, we are building for the current crate, and
173 // thus we forward the `cfg` so that `doc_auto_cfg` sees it.
174 #[macro_export]
175 #[cfg(feature = $flag)]
176 #[doc(hidden)]
177 #[cfg(feature = "__doc")]
178 macro_rules! $cfg {
179 ($d ($item:item)*) => { $d (#[cfg(feature = $flag)] $item)* };
180 }
181 #[macro_export]
182 #[cfg(not(feature = $flag))]
183 #[doc(hidden)]
184 macro_rules! $cfg {
185 ($d ($tt:tt)*) => {};
186 }
187 pub use $cfg;
188 )* };
189 }
190 use feature_flags;
191}
192
193#[cfg(feature = "__doc")]
194pub mod examples;
195
196#[test]
197#[cfg(feature = "macro")]
198// Don’t test on Nightly because the output is different to stable.
199#[cfg(not(feature = "__doc"))]
200fn ui() {
201 let t = trybuild::TestCases::new();
202 t.pass("tests/force_build.rs");
203 t.compile_fail("ui/*.rs");
204}
205
206mod unsafe_api;