1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/// A trait for handling constant and non-constant values in a common way
///
/// # Example
/// ```
/// # #[cfg(feature = "usize")] #[rustversion::since(1.51)] fn test() {
/// fn twice<T: partial_const::MayBeConst<usize>>(i: T) -> usize {
///     i.value() * 2
/// }
///
/// assert_eq!(twice(1usize), 2usize);
/// assert_eq!(twice(partial_const::ConstUsize::<1>::new()), 2usize);
/// # }
/// # #[cfg(not(feature = "usize"))] fn test(){}
/// # #[cfg(feature = "usize")] #[rustversion::not(since(1.51))] fn test(){}
/// # test();
/// ```
pub trait MayBeConst<T>: MayBeConstAT<Type=T> {}

/// A trait [MayBeConst] by associated type for internal trait bounds.
pub trait MayBeConstAT: Sized + Clone + Copy + Default + core::fmt::Debug + core::fmt::Display {
    type Type: MayBeConstAT<Type=Self::Type>;
    const IS_CONST: bool;
    fn value(&self) -> Self::Type;
}

impl<T: MayBeConstAT> MayBeConst<T::Type> for T {}

/// A trait for putting equality constraints on constants.
/// It will be implemented if the constants are equal.
///
/// # Example
/// ```
/// # #[cfg(feature = "u8")] #[rustversion::since(1.51)] fn test() {
/// fn equal<A: partial_const::MayBeConst<u8>, B: partial_const::MayBeConst<u8>>(a: A, b: B) -> bool
///     where A: partial_const::Equals<B> {
///     a.value() == b.value()
/// }
///
/// assert!(equal(partial_const::ConstU8::<1>::new(), partial_const::ConstU8::<1>::new()));
/// assert!(equal(partial_const::ConstU8::<1>::new(), 1));
/// assert!(!equal(partial_const::ConstU8::<1>::new(), 2));
/// // assert!(equal(partial_const::ConstU8::<1>::new(), partial_const::ConstU8::<2>::new())); <- Compile Error
/// # }
/// # #[cfg(not(feature = "u8"))] fn test(){}
/// # #[cfg(feature = "u8")] #[rustversion::not(since(1.51))] fn test(){}
/// # test();
/// ```
pub trait Equals<T: MayBeConstAT>: MayBeConstAT<Type=T::Type> {
    /// The const side of two types.
    /// # Example
    /// ```
    /// # #[cfg(feature = "u16")] #[rustversion::since(1.51)] fn test() {
    /// assert_eq!(<partial_const::ConstU16<0> as partial_const::Equals<partial_const::ConstU16<0>>>::ConstSide::default(), partial_const::ConstU16::<0>::new());
    /// assert_eq!(<partial_const::ConstU16<0> as partial_const::Equals<u16>>::ConstSide::default(), partial_const::ConstU16::<0>::new());
    /// assert_eq!(<u16 as partial_const::Equals<partial_const::ConstU16<0>>>::ConstSide::default(), partial_const::ConstU16::<0>::new());
    /// assert_eq!(<u16 as partial_const::Equals<u16>>::ConstSide::default(), 0_u16);
    /// # }
    /// # #[cfg(not(feature = "u16"))] fn test(){}
    /// # #[cfg(feature = "u16")] #[rustversion::not(since(1.51))] fn test(){}
    /// # test();
    /// ```
    type ConstSide: MayBeConst<T::Type>;
    /// Return the const side value of two values if two values are equal.
    /// # Example
    /// ```
    /// # #[cfg(feature = "u32")] #[rustversion::since(1.51)] fn test() {
    /// # use partial_const::{Equals,ConstU32};
    /// assert_eq!(ConstU32::<0>::new().get_const_side(&ConstU32::<0>::new()), Some(ConstU32::<0>::new()));
    /// assert_eq!(ConstU32::<0>::new().get_const_side(&0_u32), Some(ConstU32::<0>::new()));
    /// assert_eq!(0_u32.get_const_side(&ConstU32::<0>::new()), Some(ConstU32::<0>::new()));
    /// assert_eq!(0_u32.get_const_side(&0_u32), Some(0_u32));
    ///
    /// assert_eq!(ConstU32::<0>::new().get_const_side(&1_u32), None);
    /// assert_eq!(1_u32.get_const_side(&ConstU32::<0>::new()), None);
    /// assert_eq!(0_u32.get_const_side(&1_u32), None);
    /// # }
    /// # #[cfg(not(feature = "u32"))] fn test(){}
    /// # #[cfg(feature = "u32")] #[rustversion::not(since(1.51))] fn test(){}
    /// # test();
    /// ```
    fn get_const_side(&self, rhs: &T) -> Option<Self::ConstSide>;
}

macro_rules! impl_stable {
    ($t:tt) => {
        impl crate::MayBeConstAT for $t {
            type Type = $t;
            const IS_CONST: bool = false;
            #[inline(always)]
            fn value(&self) -> $t {
                *self
            }
        }

        impl crate::Equals<$t> for $t {
            type ConstSide = $t;
            fn get_const_side(&self, rhs: &$t) -> Option<Self::ConstSide> {
                if *self == *rhs {
                    Some(*self)
                } else {
                    None
                }
            }
        }

        #[cfg(test)]
        mod test_stable {
            #[test]
            fn test_equals() {
                fn test<A: crate::MayBeConst<$t>, B: crate::MayBeConst<$t>>() where A: crate::Equals<B> {}
                test::<$t, $t>();
            }

            #[test]
            fn test_is_const() {
                assert!(!<$t as crate::MayBeConstAT>::IS_CONST);
            }
        }
    }
}