Skip to content

Commit

Permalink
Documentation and cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
rick-de-water committed Oct 3, 2024
1 parent 33a642d commit 6ff56d4
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 86 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.vs*/
/target
target/
doc/
Cargo.lock
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ name = "nonany"
readme = "README.md"
repository = "https://github.com/rick-de-water/nonany"
rust-version = "1.56"
version = "0.2.0"
version = "0.2.1"
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ assert_eq!(foo.get(), 25, "The value can be loaded");
## Provided types
nonmax defines generic types with user defined niches for all integer types, as well as type aliases common use cases:

| | `NonAny` | `NonMin` | `NonMax` | `NonZero` |
| | `NonAny*` | `NonMin*` | `NonMax*` | `NonZero*` |
|---|---|---|---|---|
| `i8` | [`NonAnyI8`](https://docs.rs/nonany/latest/nonany/struct.NonAnyI8.html) | [`NonMinI8`](https://docs.rs/nonany/latest/nonany/type.NonMinI8.html) | [`NonMaxI8`](https://docs.rs/nonany/latest/nonany/type.NonMaxI8.html) | [`NonZeroI8`](https://docs.rs/nonany/latest/nonany/type.NonZeroI8.html) |
| `i16` | [`NonAnyI16`](https://docs.rs/nonany/latest/nonany/struct.NonAnyI16.html) | [`NonMinI16`](https://docs.rs/nonany/latest/nonany/type.NonMinI16.html) | [`NonMaxI16`](https://docs.rs/nonany/latest/nonany/type.NonMaxI16.html) | [`NonZeroI16`](https://docs.rs/nonany/latest/nonany/type.NonZeroI16.html) |
Expand All @@ -42,9 +42,9 @@ nonmax defines generic types with user defined niches for all integer types, as


## How does it work?
Internally all `NonAny` types use the `NonZero` types from the standard library. When a value is stored in `NonAny`, the value is stored in the internal `NonZero` as an XOR of the value and the niche. Any value XORed with the niche that isn't the niche itself can never be zero, so this works out perfectly.
Internally all `NonAny*` types use the `NonZero*` types from the standard library. When a value is stored in `NonAny*`, the value is stored in the internal `NonZero*` as an XOR of the value and the niche. Any value XORed with the niche that isn't the niche itself can never be zero, so this works out perfectly.

The upside of this technique is that it works on stable rust. The downside is that it requires an, albeit cheap, XOR operation to load and store the value. Additionally, unlike the `NonZero` types, transmuting `NonAny` types to their underlying integer types results in a value that was XORed with the niche, instead of the value itself.
The upside of this technique is that it works on stable rust. The downside is that it requires an, albeit cheap, XOR operation to load and store the value. Additionally, unlike the `NonZero*` types, transmuting `NonAny*` types to their underlying integer types results in a value that was XORed with the niche, instead of the value itself.

## MSRV
The MSRV is fixed at currently 1.56.0, and the intention is to keep it there at least until version 1.0 is released.
Expand Down
169 changes: 88 additions & 81 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,124 +1,131 @@
#![no_std]
#![doc = include_str!("../README.md")]

/// An error type used to differentiate between overflow and niche errors.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum CheckedError {
Overflow,
Niche,
}

macro_rules! nonany {
($name:ident, $nonzero:ident, $int:ty) => {
/// An integer that is known not to equal zero.
($name:ident, $nonzero:ident, $int:ty, $signed:ident) => {
/// An integer that is known not to equal `NICHE`.
///
/// This enables some memory layout optimization.
#[doc = concat!("For example, `Option<", stringify!($name), "<0>>` is the same size as `", stringify!($int), "`:")]
///
/// ```rust
#[doc = concat!("assert_eq!(core::mem::size_of::<Option<nonany::", stringify!($name), "<0>>>(), core::mem::size_of::<", stringify!($int), ">());")]
/// ```
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct $name<const NICHE: $int>(core::num::$nonzero);

impl<const NICHE: $int> $name<NICHE> {
/// The niche value of this integer type.
pub const NICHE: $int = NICHE;

/// The size of this integer type in bits.
pub const BITS: u32 = <$int>::BITS;

/// Creates a non-any if the given value is not `NICHE`.
pub const fn new(value: $int) -> Option<Self> {
match core::num::$nonzero::new(value ^ NICHE) {
Some(value) => Some(Self(value)),
None => None
}
}

/// Creates a non-any without checking whether the value is `NICHE`.
/// This results in undefined behaviour if the value is `NICHE`.
///
/// # Safety
///
/// The value must not be `NICHE`.
pub const unsafe fn new_unchecked(value: $int) -> Self {
Self(core::num::$nonzero::new_unchecked(value ^ NICHE))
}

/// Returns the contained value as a primitive type.
pub const fn get(self) -> $int {
self.0.get() ^ NICHE
}

nonany!(@signed, $signed, $name, $nonzero, $int);
}
};
}

macro_rules! nonany_signed {
($name:ident, $nonzero:ident, $int:ty) => {
nonany!($name, $nonzero, $int);

impl<const NICHE: $int> $name<NICHE> {
pub const fn abs(self) -> Option<Self> {
let value = self.get().abs();
Self::new(value)
}
(@signed, true, $name:ident, $nonzero:ident, $int:ty) => {
pub const fn abs(self) -> Option<Self> {
let value = self.get().abs();
Self::new(value)
}

pub const fn checked_abs(self) -> Result<Self, CheckedError> {
match self.get().checked_abs() {
Some(value) => match Self::new(value) {
Some(value) => Ok(value),
None => Err(CheckedError::Niche)
},
None => Err(CheckedError::Overflow)
}
pub const fn checked_abs(self) -> Result<Self, CheckedError> {
match self.get().checked_abs() {
Some(value) => match Self::new(value) {
Some(value) => Ok(value),
None => Err(CheckedError::Niche)
},
None => Err(CheckedError::Overflow)
}
}

pub const fn is_positive(self) -> bool {
self.get().is_positive()
}
pub const fn is_positive(self) -> bool {
self.get().is_positive()
}

pub const fn is_negative(self) -> bool {
self.get().is_negative()
}
pub const fn is_negative(self) -> bool {
self.get().is_negative()
}
};


(@signed, false, $name:ident, $nonzero:ident, $int:ty) => {

};
}
nonany!(NonAnyU8, NonZeroU8, u8);
nonany!(NonAnyU16, NonZeroU16, u16);
nonany!(NonAnyU32, NonZeroU32, u32);
nonany!(NonAnyU64, NonZeroU64,u64);
nonany!(NonAnyU128, NonZeroU128,u128);
nonany!(NonAnyUsize, NonZeroUsize,usize);

nonany_signed!(NonAnyI8, NonZeroI8, i8);
nonany_signed!(NonAnyI16, NonZeroI16, i16);
nonany_signed!(NonAnyI32, NonZeroI32, i32);
nonany_signed!(NonAnyI64, NonZeroI64, i64);
nonany_signed!(NonAnyI128, NonZeroI128, i128);
nonany_signed!(NonAnyIsize, NonZeroIsize, isize);

pub type NonZeroI8 = NonAnyI8<0>;
pub type NonZeroI16 = NonAnyI16<0>;
pub type NonZeroI32 = NonAnyI32<0>;
pub type NonZeroI64 = NonAnyI64<0>;
pub type NonZeroI128 = NonAnyI128<0>;
pub type NonZeroIsize = NonAnyIsize<0>;

pub type NonMinI8 = NonAnyI8<{ i8::MIN }>;
pub type NonMinI16 = NonAnyI16<{ i16::MIN }>;
pub type NonMinI32 = NonAnyI32<{ i32::MIN }>;
pub type NonMinI64 = NonAnyI64<{ i64::MIN }>;
pub type NonMinI128 = NonAnyI128<{ i128::MIN }>;
pub type NonMinIsize = NonAnyIsize<{ isize::MIN }>;

pub type NonMaxI8 = NonAnyI8<{ i8::MAX }>;
pub type NonMaxI16 = NonAnyI16<{ i16::MAX }>;
pub type NonMaxI32 = NonAnyI32<{ i32::MAX }>;
pub type NonMaxI64 = NonAnyI64<{ i64::MAX }>;
pub type NonMaxI128 = NonAnyI128<{ i128::MAX }>;
pub type NonMaxIsize = NonAnyIsize<{ isize::MAX }>;

pub type NonZeroU8 = NonAnyI8<0>;
pub type NonZeroU16 = NonAnyI16<0>;
pub type NonZeroU32 = NonAnyI32<0>;
pub type NonZeroU64 = NonAnyI64<0>;
pub type NonZeroU128 = NonAnyI128<0>;
pub type NonZeroUsize = NonAnyIsize<0>;

pub type NonMinU8 = NonAnyU8<{ u8::MIN }>;
pub type NonMinU16 = NonAnyU16<{ u16::MIN }>;
pub type NonMinU32 = NonAnyU32<{ u32::MIN }>;
pub type NonMinU64 = NonAnyU64<{ u64::MIN }>;
pub type NonMinU128 = NonAnyU128<{ u128::MIN }>;
pub type NonMinUsize = NonAnyUsize<{ usize::MIN }>;

pub type NonMaxU8 = NonAnyU8<{ u8::MAX }>;
pub type NonMaxU16 = NonAnyU16<{ u16::MAX }>;
pub type NonMaxU32 = NonAnyU32<{ u32::MAX }>;
pub type NonMaxU64 = NonAnyU64<{ u64::MAX }>;
pub type NonMaxU128 = NonAnyU128<{ u128::MAX }>;
pub type NonMaxUsize = NonAnyUsize<{ usize::MAX }>;

nonany!(NonAnyU8, NonZeroU8, u8, false);
nonany!(NonAnyU16, NonZeroU16, u16, false);
nonany!(NonAnyU32, NonZeroU32, u32, false);
nonany!(NonAnyU64, NonZeroU64, u64, false);
nonany!(NonAnyU128, NonZeroU128, u128, false);
nonany!(NonAnyUsize, NonZeroUsize, usize, false);

nonany!(NonAnyI8, NonZeroI8, i8, true);
nonany!(NonAnyI16, NonZeroI16, i16, true);
nonany!(NonAnyI32, NonZeroI32, i32, true);
nonany!(NonAnyI64, NonZeroI64, i64, true);
nonany!(NonAnyI128, NonZeroI128, i128, true);
nonany!(NonAnyIsize, NonZeroIsize, isize, true);

macro_rules! nonany_typedef {
($nonzero:ident, $nonmin:ident, $nonmax:ident, $nonany:ident, $int:ident) => {
/// An integer that is known not to equal zero.
pub type $nonzero = $nonany<0>;

#[doc = concat!("An integer that is known not to equal `", stringify!($int), "::MIN`.")]
pub type $nonmin = $nonany<{ $int::MIN }>;

#[doc = concat!("An integer that is known not to equal `", stringify!($int), "::MAX`.")]
pub type $nonmax = $nonany<{ $int::MAX }>;
}
}

nonany_typedef!(NonZeroI8, NonMinI8, NonMaxI8, NonAnyI8, i8);
nonany_typedef!(NonZeroI16, NonMinI16, NonMaxI16, NonAnyI16, i16);
nonany_typedef!(NonZeroI32, NonMinI32, NonMaxI32, NonAnyI32, i32);
nonany_typedef!(NonZeroI64, NonMinI64, NonMaxI64, NonAnyI64, i64);
nonany_typedef!(NonZeroI128, NonMinI128, NonMaxI128, NonAnyI128, i128);
nonany_typedef!(NonZeroIsize, NonMinIsize, NonMaxIsize, NonAnyIsize, isize);

nonany_typedef!(NonZeroU8, NonMinU8, NonMaxU8, NonAnyU8, u8);
nonany_typedef!(NonZeroU16, NonMinU16, NonMaxU16, NonAnyU16, u16);
nonany_typedef!(NonZeroU32, NonMinU32, NonMaxU32, NonAnyU32, u32);
nonany_typedef!(NonZeroU64, NonMinU64, NonMaxU64, NonAnyU64, u64);
nonany_typedef!(NonZeroU128, NonMinU128, NonMaxU128, NonAnyU128, u128);
nonany_typedef!(NonZeroUsize, NonMinUsize, NonMaxUsize, NonAnyUsize, usize);

#[cfg(test)]
mod tests;

0 comments on commit 6ff56d4

Please sign in to comment.