const_generic_wrap/
lib.rs

1//! Simple wrapper for const generics.
2//! # Usage
3//! Currently 'the type of const parameters must not depend on other generic parameters' (E0770).
4//! ```compile_fail
5//! struct A<N, const C : N>(N);
6//! ```
7//! With this crate we can solve this by wrapping cosnt generic.
8//! ```
9//! # use core::mem;
10//! # use core::ops::Add;
11//! use const_generic_wrap::*;
12//! struct A<N, C>(N, C) where C : ConstWrap<BaseType = N>;
13//! // WrapU32 is ZST, so the size of A is as same as u32.
14//! assert_eq!(mem::size_of::<WrapU32<12>>(), 0);
15//! assert_eq!(mem::size_of::<A::<u32, WrapU32<12>>>(), mem::size_of::<u32>());
16//!
17//! // you can selectively use const or non const
18//! struct B<N, C>(N, C) where C : ConstOrValue<N>, N : Constable; // or it can be C : Into<N>
19//! fn add_b<N, C>(v : B<N, C>) -> N where N : Add<Output = N> + Constable, C : ConstOrValue<N>{
20//!     v.0 + v.1.into()
21//! }
22//! let b_non_const = B(31, 11);
23//! let b_const = B(31, WrapI32::<11>);
24//! assert_eq!(add_b(b_non_const), add_b(b_const));
25//! ```
26
27#![no_std]
28#![cfg_attr(feature = "unstable", feature(const_evaluatable_checked))]
29#![cfg_attr(feature = "unstable", feature(const_generics))]
30
31use core::cmp::Ordering;
32pub(crate) use seal::*;
33mod seal {
34    /// Seal the ConstWrap not to be implemented with outer type.
35    pub trait WrapSeal {}
36    /// Seal the Constable not to be implemented with outer type.
37    pub trait ConstableSeal {}
38}
39
40/// Marker that shows it wraps const generic.
41pub trait ConstWrap:
42    Clone + Copy + Default + Eq + core::hash::Hash + PartialEq + PartialOrd + Ord + WrapSeal
43{
44    /// Type which is wrapped.
45    type BaseType: Constable;
46    /// Value which is wrapped.
47    const VALUE: Self::BaseType;
48}
49
50/// Trait that can be a wrapped const generic or a owned value.
51pub trait ConstOrValue<T>: Into<T> {
52    /// get wheter the type is const generic wrapper.
53    const IS_CONST_WRAP: bool;
54}
55
56impl<T> ConstOrValue<T> for T {
57    const IS_CONST_WRAP: bool = false;
58}
59
60/// Marker that shows it can be used in const generic.
61pub trait Constable: ConstableSeal {}
62
63/// A lists of types for a specified values.
64pub trait ConstIntTypes: Constable {
65    type Zero: ConstWrap;
66    type One: ConstWrap;
67}
68
69/// Failed to convert to const wrap type. 
70#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
71pub struct MismatchConstError;
72
73macro_rules! wrap_impl {
74    ($tb: ty, $t : ident) => {
75        /// Const generic wrapper.
76        #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
77        pub struct $t<const T: $tb>;
78        impl ConstableSeal for $tb{}
79        impl Constable for $tb {}
80        impl<const T: $tb> WrapSeal for $t<T>{}
81        impl<const T: $tb> ConstWrap for $t<T> {
82            type BaseType = $tb;
83            const VALUE : $tb = T;
84        }
85        impl<const T: $tb> ConstOrValue<$tb> for $t<T> {
86            const IS_CONST_WRAP : bool = true;
87        }
88        impl<const T: $tb> From<$t<T>> for $tb {
89            fn from(_ : $t<T>) -> $tb { T }
90        }
91        impl<'a, const T: $tb> From<$t<T>> for &'a $tb {
92            fn from(_ : $t<T>) -> &'a $tb { &T }
93        }
94        impl<const T: $tb> core::convert::TryFrom<$tb> for $t<T> {
95            type Error = MismatchConstError;
96            fn try_from(value : $tb) -> Result<$t<T>, MismatchConstError> {
97                if value == T {
98                    Ok($t)
99                }else{
100                    Err(MismatchConstError)
101                }
102            }
103        }
104        impl<const T: $tb> PartialEq<$tb> for $t<T> {
105            fn eq(&self, other: &$tb) -> bool { T.eq(other)}
106        }
107        impl<const T: $tb> PartialOrd<$tb> for $t<T> {
108            fn partial_cmp(&self, other: &$tb) -> Option<Ordering> { T.partial_cmp(other)}
109        }
110    };
111    [$(($tb: ty, $t : tt)),*$(,)*] => {
112        $(
113            wrap_impl!($tb, $t);
114        )*
115    };
116}
117
118wrap_impl![
119    (u8, WrapU8),
120    (u16, WrapU16),
121    (u32, WrapU32),
122    (u64, WrapU64),
123    (usize, WrapUSIZE),
124    (i8, WrapI8),
125    (i16, WrapI16),
126    (i32, WrapI32),
127    (i64, WrapI64),
128    (isize, WrapISIZE),
129    (bool, WrapBOOL),
130    (char, WrapCHAR),
131];
132
133macro_rules! wrap_impl_ints {
134    ($tb: ty, $t : ident) => {
135        impl ConstIntTypes for $tb{
136            type Zero = $t<0>;
137            type One = $t<1>;
138        }
139    };
140    [$(($tb: ty, $t : tt)),*$(,)*] => {
141        $(
142            wrap_impl_ints!($tb, $t);
143        )*
144    };
145}
146
147wrap_impl_ints![
148    (u8, WrapU8),
149    (u16, WrapU16),
150    (u32, WrapU32),
151    (u64, WrapU64),
152    (usize, WrapUSIZE),
153    (i8, WrapI8),
154    (i16, WrapI16),
155    (i32, WrapI32),
156    (i64, WrapI64),
157    (isize, WrapISIZE),
158];
159
160#[cfg(feature = "typenum")]
161mod typenum_bridge;
162
163#[cfg(test)]
164mod tests {
165
166    use crate::*;
167    #[test]
168    fn wrap_unwrap() {
169        let n3 = WrapI32::<3>;
170        assert_eq!(0, core::mem::size_of_val(&n3));
171        let m: i32 = n3.into();
172        assert_eq!(3, m);
173    }
174}