### 4 releases

0.2.1 | May 11, 2024 |
---|---|

0.2.0 | Jan 21, 2024 |

0.1.1 | Jan 10, 2024 |

0.1.0 | Jan 10, 2024 |

#**240** in Rust patterns

**186** downloads per month

**MIT**license

**5MB**

12K
SLoC

# Bounded-integer types focused on ergonomics and safety.

The goal of this crate is to allow users to fearlessly use bounded integers without worrying about checking the operations performed on them.

There is one exception: division by zero will still panic.

### Make sure to carefully read this README before using it.

### Since all bounded types behave equally, this README is the entire documentation.

- No unsafe code.
- All operations are saturated, no overflow/underflow, no wrapping.
- Division by zero still panics.
- Focused on ergonomics(comfyness): operations with different integer types (e.g. i8 and i16) are allowed, those are evaluated using a larger type, then the result is saturated to the target type.
- Operations will always be at least as slow as the std::saturating operations. If you need speed, consider getting a copy of the inner value using

or the`.``get``(``)``deref`

operator.`*` - Mostly test-covered. Currently, the derived

/`Hash`

/`PartialOrd`

traits are not covered by unit tests.`Ord`

## Features

All features are disabled by default.

: Enables unchecked division by zero. (Division by non-zero types (NonZeroI8, ...) is provided without this feature).`div_assign_zero`

: Enables serde Serialization/Deserialization support, all bounded types are serialized transparently as their inner value. Example:`serde`

.`assert_eq!``(``serde_json`to_string`::``(``&``Bound_i8``::``<`0, 10`>`new`::``(``5``)``)``.``unwrap``(``)``,``serde_json`to_string`::``(``&``5_``i8``)``.``unwrap``(``)``)`

# Quirks

## All rust signed/unsigned types are supported: i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize

`use` `comfy_bounded_ints``::``{`
Bound_i8`,` Bound_i16`,` Bound_i32`,` Bound_i64`,` Bound_i128`,` Bound_isize`,`
Bound_u8`,` Bound_u16`,` Bound_u32`,` Bound_u64`,` Bound_u128`,` Bound_usize
`}``;`

## Constraints are enforced at compile-time, you specify them using const params

Use the

function to create a new bounded type.
`new`

will not compile if MIN > MAX`cargo`` build`

`use` `comfy_bounded_ints``::`Bound_i16`;`
`let` bounded `=` `Bound_i16``::``<`20, 50`>``::`new`(``30``)``;`
`^``^``^``^``^``^`

## This crate guarantees that the inner value will always be within the specified range

No operations can violate this rule.

`use` `comfy_bounded_ints``::`Bound_i32`;`
`let` bounded `=` `Bound_i32``::``<`20, 50`>``::`new`(``80``)``;`
`assert_eq!``(`bounded`.``get``(``)``,` `50``)``;`
`^``^``^``^``^``^``^``^``^``^``^``^``^``^``^``^``^`
`let` bounded `=` `Bound_i32``::``<`20, 50`>``::`new`(``10``)``;`
`assert_eq!``(`bounded`.``get``(``)``,` `20``)``;`
`^``^``^``^``^``^``^``^``^``^``^``^``^``^``^``^``^`

## You can get a copy of the inner value using the `.``get``(``)`

method or the `deref`

`*`

operator

`.``get``(``)``deref`

`*``use` `comfy_bounded_ints``::`Bound_i64`;`
`let` bounded `=` `Bound_i64``::``<`20, 50`>``::`new`(``30``)``;`
`assert_eq!``(`bounded`.``get``(``)``,` `30``)``;`
`^``^``^``^``^``^`
`assert_eq!``(``*`bounded`,` `30``)``;`
`^`

## Note that none of the bounded types implement `DerefMut`

, as this would allow violating the constraints.

`DerefMut`

If you want to mutate the inner value, you can use the

method, or any of the assign operators.`.``set``(``)`

`use` `comfy_bounded_ints``::`Bound_isize`;`
`let` `mut` bounded `=` `Bound_isize``::``<`20, 50`>``::`new`(``30``)``;`
bounded`.``set``(``40``)``;`
`^``^``^``^``^``^``^``^`
`assert_eq!``(`bounded`.``get``(``)``,` `40``)``;`
bounded `+=` `10``;`
`^``^`
`assert_eq!``(`bounded`.``get``(``)``,` `50``)``;`
bounded`.``set``(``10``)``;`
`^``^``^``^``^``^``^``^`
`assert_eq!``(`bounded`.``get``(``)``,` `20``)``;`
bounded`.``set``(``80``)``;`
`^``^``^``^``^``^``^``^`
`assert_eq!``(`bounded`.``get``(``)``,` `50``)``;`
bounded `-=` `10``;`
`^``^`
`assert_eq!``(`bounded`.``get``(``)``,` `40``)``;`
bounded `/=` `2``;`
`^``^`
`assert_eq!``(`bounded`.``get``(``)``,` `20``)``;`
bounded `*=` `2``;`
`^``^`
`assert_eq!``(`bounded`.``get``(``)``,` `40``)``;`
bounded `%=` `30``;`
`^``^`
`assert_eq!``(`bounded`.``get``(``)``,` `20``)``;`

`AddAssign`

/`SubAssign`

/`MulAssign`

/`DivAssign`

/`RemAssign`

`AddAssign`

`SubAssign`

`MulAssign`

`DivAssign`

`RemAssign`

Are allowed between different integer types, as well as bounded types with different constraints.
The regular

/`Add`

/`Sub`

/`Mul`

/`Div`

operations are not supported, use `Rem`

or `.`get`*`

to perform them on the inner value instead.
Support for the regular operations is not provided due to ambiguity in which type should be returned.`deref`

`use` `comfy_bounded_ints``::``{`Bound_i8`,` Bound_i16`,` Bound_u8`,` Bound_u32`,` Bound_isize`}``;`
`let` `mut` bounded_i8 `=` `Bound_i8``::``<`20, 50`>``::`new`(``30``)``;`
`let` bounded_i16 `=` `Bound_i16``::``<` `-``200``,` `500``>``::`new`(``-``200``)``;`
bounded_i8 `+=` bounded_i16`;`
`^``^`
`assert_eq!``(`bounded_i8`.``get``(``)``,` `20``)``;`
`let` `mut` bounded_i8 `=` `Bound_i8``::``<` `-``128``,` `127``>``::`new`(``-``128``)``;`
`let` bounded_i16 `=` `Bound_i16``::``<` `-``300``,` `500``>``::`new`(``-``300``)``;`
bounded_i8 `-=` bounded_i16`;`
`^``^`
`assert_eq!``(`bounded_i8`.``get``(``)``,` `127``)``;`
`let` `mut` bounded_u8 `=` `Bound_u8``::``<` 5, 80`>``::`new`(``70``)``;`
`let` bounded_i16 `=` `Bound_i16``::``<` `-``300``,` `500``>``::`new`(``-``1``)``;`
bounded_u8 `*=` bounded_i16`;`
`^``^`
`assert_eq!``(`bounded_u8`.``get``(``)``,` `5``)``;`
`let` `mut` bounded_u32 `=` `Bound_u8``::``<` 2, 650`>``::`new`(``800``)``;`
`let` bounded_i8 `=` `Bound_i8``::``<` `-``30``,` `10``>``::`new`(``-``1``)``;`
bounded_u32 `/=` bounded_i8`;`
`^``^`
`assert_eq!``(`bounded_u32`.``get``(``)``,` `2``)``;`
`let` `mut` bounded_u32 `=` `Bound_u32``::``<` 3, 650`>``::`new`(``800``)``;`
`let` bounded_i8 `=` `Bound_i8``::``<` `-``30``,` `10``>``::`new`(``-``1``)``;`
bounded_u32 `%=` bounded_i8`;`
`^``^`
`assert_eq!``(`bounded_u32`.``get``(``)``,` `3``)``;`
`let` `mut` bounded_isize `=` `Bound_isize``::``<`0, 200`>``::`new`(``80``)``;`
`let` int_i8 `=` `30_``i8``;`
bounded_isize `+=` int_i8`;`
`^``^`
`assert_eq!``(`bounded_isize`.``get``(``)``,` `110``)``;`
`let` `mut` bounded_isize `=` `Bound_isize``::``<`0, 200`>``::`new`(``80``)``;`
`let` int_i32 `=` `-``900_``i32``;`
bounded_isize `+=` int_i32`;`
`^``^`
`assert_eq!``(`bounded_isize`.``get``(``)``,` `0``)``;`
`...`

## The `Default`

trait is implemented for all bounded types

`Default`It creates a new bounded type with the minimum value as the inner value.

## All bounded types #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, Eq)]

## All bounded types implement DivAssign/RemAssign for their respective NonZero type

This **does not** require the

feature.`div_assign_zero`

`use` `comfy_bounded_ints``::``{`Bound_i8`,` Bound_u128`}``;`
`let` `mut` bounded_i8 `=` `Bound_i8``::``<` `-``30``,` `80``>``::`new`(``-``120``)``;`
`let` non_zero_i8 `=` `NonZeroI8``::`new`(``-``2``)``.``unwrap``(``)``;`
bounded_i8 `*=` non_zero_i8`;`
`^``^`
`assert_eq!``(`bounded_i8`.``get``(``)``,` `60``)``;`
`let` `mut` bounded_u128 `=` `Bound_u128``::``<` 3, 650`>``::`new`(``800``)``;`
`let` non_zero_u128 `=` `NonZeroU128``::`new`(``2``)``.``unwrap``(``)``;`
bounded_u128 `/=` non_zero_u128`;`
`^``^`
`assert_eq!``(`bounded_u128`.``get``(``)``,` `325``)``;`

## All bounded types can be created from any integer type using the `From`

trait

`From`This trait also provides a blanket implementation allowing any integer to be converted to a given bounded type using the method

.`.``into``(``)`

`use` `comfy_bounded_ints``::``{`Bound_i8`,` Bound_isize`,` Bound_u8`,` Bound_u32`}``;`
`let` bounded_i8 `=` `Bound_i8``::``<` `-``30``,` `80``>``::`from`(``-``120_``i8``)``;`
`^``^``^``^``^``^``^``^``^``^``^``^``^`
`assert_eq!``(`bounded_i8`.``get``(``)``,` `-``30``)``;`
`let` bounded_u32 `=` `Bound_u32``::``<` 2, 650`>``::`from`(``-``800_``i32``)``;`
`^``^``^``^``^``^``^``^``^``^``^``^``^``^`
`assert_eq!``(`bounded_u32`.``get``(``)``,` `2``)``;`
`let` bounded_isize`:` `Bound_isize``<`20, 100`>` `=` `50_``u128``.``into``(``)``;`
`^``^``^``^``^``^``^`
`assert_eq!``(`bounded_isize`.``get``(``)``,` `50``)``;`
`let` bounded_u8`:` `Bound_u8``<`20, 100`>` `=` `-``50_``i64``.``into``(``)``;`
`^``^``^``^``^``^``^`
`assert_eq!``(`bounded_u8`.``get``(``)``,` `20``)``;`

## PartialEq is implemented between bounded types with the same inner integer type

Constraints are irrelevant for this comparison.
For other comparisons, you can use the

method or the `.``get``(``)``deref`

operator, then compare using the inner values.`*`

`use` `comfy_bounded_ints``::``{`Bound_i8`,` Bound_u16`}``;`
`let` a_i8 `=` `Bound_i8``::``<` `-``30``,` `80``>``::`new`(``-``120``)``;`
`let` b_i8 `=` `Bound_i8``::``<` `-``30``,` `80``>``::`new`(``20``)``;`
`assert!``(`a_i8 `!=` b_i8`)``;`
`let` a_u16 `=` `Bound_u16``::``<` 2, 650`>``::`new`(``800``)``;`
`let` b_u16 `=` `Bound_u16``::``<` 2, 650`>``::`new`(``650``)``;`
`assert!``(`a_u16 `==` b_u16`)``;`