use crate::op_mode;
use paste::paste;
use std::marker::PhantomData;
macro_rules! gen_ranged_structs {
($i:ty) => {
paste!{
#[derive(Debug, Clone, Copy)]
#[doc = "A ranged integer between MIN and MAX, encapsulating [" $i "] type.\n\n"]
#[doc=[<Ranged $i:upper>]"<MIN, MAX, OpMode>"]
pub struct [<Ranged $i:upper>]<const MIN: $i = {$i::MIN}, const MAX:$i = {$i::MAX}, OpMode=op_mode::Panic>($i, PhantomData<OpMode>) where OpMode: op_mode::OpModeExt;
#[doc = "A ranged integer between the provided MIN and [" $i "::MAX].\n\n"]
pub type [<Ranged $i:upper Min>]<const MIN:$i, OpMode=op_mode::Panic> = [<Ranged $i:upper>]<MIN, {$i::MAX}, OpMode>;
#[doc = "A ranged integer between [" $i "::MIN] and the provided MAX.\n\n"]
pub type [<Ranged $i:upper Max>]<const MAX:$i, OpMode=op_mode::Panic> = [<Ranged $i:upper>]<{$i::MIN}, MAX, OpMode>;
impl<OpMode, const MIN: $i, const MAX:$i> [<Ranged $i:upper>]<MIN, MAX, OpMode> where OpMode: op_mode::OpModeExt
{
const COMPTIME_RANGE_CHECK: () = assert!(MIN < MAX, "INVALID RANGE. MIN must be smaller than MAX");
#[doc="Builds a new [" [<Ranged $i:upper>]"] checking the limits at runtime"]
pub fn new(v: $i) -> Self
{
let _ = Self::COMPTIME_RANGE_CHECK;
assert!(MIN<MAX);
let v = OpMode::bring_in_range(v, MIN, MAX);
Self(v, PhantomData)
}
#[doc="use light_ranged_integers::"[<Ranged $i:upper>]";"]
#[doc="let m = "[<Ranged $i:upper>]"::<1,4>::const_new::<2>();"]
#[doc="use light_ranged_integers::"[<Ranged $i:upper>]";"]
#[doc="let m = "[<Ranged $i:upper>]"::<1,4>::const_new::<5>();"]
pub const fn const_new<const V: $i>() -> [<Ranged $i:upper>]::<MIN, MAX, OpMode>
{
const_ranged::[<ConstRanged $i:upper>]::<MIN, MAX, V>::new().as_ranged::<OpMode>()
}
#[doc="Tries to construct a "[<Ranged $i:upper>]""]
pub fn maybe_new(value: $i) -> Option<Self>
{
if value >= MIN && value <= MAX
{
return Some(Self::new(value))
}
else
{
return None
}
}
#[doc="Limits the value to a new minimum and maximum."]
pub fn limit<const NEW_MIN: $i, const NEW_MAX: $i>(self) -> [<Ranged $i:upper>]<NEW_MIN, NEW_MAX, OpMode>
{
[<Ranged $i:upper>]::<NEW_MIN, NEW_MAX, OpMode>::new(self.0)
}
#[doc="Limits the value to a new minimum; keeps the previous maximum value limit."]
pub fn limit_min<const NEW_MIN:$i>(self) -> [<Ranged $i:upper>]<NEW_MIN, MAX, OpMode>
{
self.limit::<NEW_MIN, MAX>()
}
#[doc="Limits the value to a new maximum; keeps the previous minimum value limit."]
pub fn limit_max<const NEW_MAX:$i>(self) -> [<Ranged $i:upper>]<MIN, NEW_MAX, OpMode>
{
self.limit::<MIN, NEW_MAX>()
}
pub const fn inner(&self) -> $i {self.0}
}
impl<OpMode, const MIN: $i, const MAX:$i> std::cmp::PartialEq<$i> for [<Ranged $i:upper>]<MIN, MAX, OpMode> where OpMode: op_mode::OpModeExt
{
fn eq(&self, other: &$i) -> bool
{
self.0.eq(other)
}
}
impl<OpMode, const MIN: $i, const MAX:$i> std::cmp::PartialEq for [<Ranged $i:upper>]<MIN, MAX, OpMode> where OpMode: op_mode::OpModeExt
{
fn eq(&self, other: &[<Ranged $i:upper>]<MIN, MAX, OpMode>) -> bool
{
self.0.eq(&other.0)
}
}
impl<OpMode, const MIN: $i, const MAX:$i> std::cmp::PartialOrd<$i> for [<Ranged $i:upper>]<MIN, MAX, OpMode> where OpMode: op_mode::OpModeExt
{
fn partial_cmp(&self, other: &$i) -> Option<std::cmp::Ordering>
{
self.0.partial_cmp(other)
}
}
impl<OpMode, const MIN: $i, const MAX:$i> std::cmp::PartialOrd for [<Ranged $i:upper>]<MIN, MAX, OpMode> where OpMode: op_mode::OpModeExt
{
fn partial_cmp(&self, other: &[<Ranged $i:upper>]<MIN, MAX, OpMode>) -> Option<std::cmp::Ordering>
{
self.0.partial_cmp(&other.0)
}
}
impl<OpMode, const MIN: $i, const MAX:$i> From<$i> for [<Ranged $i:upper>]<MIN,MAX,OpMode>
where OpMode: op_mode::OpModeExt
{
fn from(value: $i) -> Self {
Self::new(value)
}
}
}
};
}
gen_ranged_structs!(u8);
gen_ranged_structs!(u16);
gen_ranged_structs!(u32);
gen_ranged_structs!(u64);
gen_ranged_structs!(i8);
gen_ranged_structs!(i16);
gen_ranged_structs!(i32);
gen_ranged_structs!(i64);
pub mod const_ranged
{
use super::*;
use crate::op_mode;
use paste::paste;
macro_rules! gen_const_ranged_structs {
($i:ty) => {
paste!{
#[derive(Clone, Copy)]
#[doc = "A compile-time checked [" [<Ranged $i:upper>] "] struct.\n\n"]
pub struct [<ConstRanged $i:upper>]<const MIN:$i, const MAX:$i, const V: $i>;
impl<const MIN:$i, const MAX:$i, const V: $i> [<ConstRanged $i:upper>]<MIN,MAX,V>
{
const RANGE_VALID: () = assert!(MIN<MAX, "The range is not valid. MIN must be smaller than MAX");
const IS_IN_RANGE: () = assert!(V>=MIN && V<=MAX, "Provided value V is outside of the range");
/// Creates a new compile-checked range number.
/// The number MUST be in range to compile correctly,
/// independently of the [OpMode](op_mode)
pub const fn new() -> Self
{
let _ = Self::RANGE_VALID;
let _ = Self::IS_IN_RANGE;
return [<ConstRanged $i:upper>]::<MIN,MAX,V>
}
/// Converts to a runtime Ranged value, assigning the provided OpMode
pub const fn as_ranged<OpMode: op_mode::OpModeExt>(&self) -> [<Ranged $i:upper>]<MIN,MAX,OpMode>
{
return [<Ranged $i:upper>]::<MIN,MAX,OpMode>(V, PhantomData)
}
/// Returns the inner value alone
pub const fn inner(self) -> $i
{
V
}
pub const fn get_limits(self) -> ($i,$i)
{
(MIN,MAX)
}
#[doc="Limits the value to a new minimum and maximum."]
///
/// Makes sure the new limits will be respected
/// ```
/// use light_ranged_integers::const_ranged::*;
/// // Value 5 fits [0,10], and also [0,5]
#[doc=""[<ConstRanged $i:upper>]"::<0,10,5>::new().limit::<0,5>();"]
/// ```
///
///
/// Raises a compile error if the value does not fit the new limit
/// ```compile_fail
/// use light_ranged_integers::const_ranged::*;
/// // Value 5 fits [0,10], but not [0,3]
#[doc=""[<ConstRanged $i:upper>]"::<0,10,5>::new().limit::<0,3>();"]
/// ```
pub const fn limit<const NEW_MIN:$i, const NEW_MAX:$i>(self) -> [<ConstRanged $i:upper>]::<NEW_MIN, NEW_MAX,V>
{
return [<ConstRanged $i:upper>]::new()
}
#[doc="Limits the value to a new minimum; keeps the previous maximum value limit."]
pub const fn limit_min<const NEW_MIN:$i>(self) -> [<ConstRanged $i:upper>]::<NEW_MIN, MAX,V>
{
self.limit::<NEW_MIN, MAX>()
}
#[doc="Limits the value to a new maximum; keeps the previous minimum value limit."]
pub const fn limit_max<const NEW_MAX:$i>(self) -> [<ConstRanged $i:upper>]::<MIN, NEW_MAX,V>
{
self.limit::<MIN, NEW_MAX>()
}
}
}
}}
gen_const_ranged_structs!(u8);
gen_const_ranged_structs!(u16);
gen_const_ranged_structs!(u32);
gen_const_ranged_structs!(u64);
gen_const_ranged_structs!(i8);
gen_const_ranged_structs!(i16);
gen_const_ranged_structs!(i32);
gen_const_ranged_structs!(i64);
}