#![no_std]
#![allow(dead_code)]
#[macro_export]
#[doc(hidden)]
macro_rules! __encap_enum_impl {
($name:ident, $type:ty) => {
impl core::ops::BitOr for $name {
type Output = Self;
fn bitor(self, right: Self) -> Self { Self{raw: self.raw | right.raw} }
}
impl core::ops::Add for $name {
type Output = Self;
fn add(self, right: Self) -> Self { Self{raw: self.raw + right.raw} }
}
impl core::ops::BitAnd for $name {
type Output = Self;
fn bitand(self, right: Self) -> Self { Self{raw: self.raw & right.raw} }
}
impl core::ops::BitXor for $name {
type Output = Self;
fn bitxor(self, right: Self) -> Self { Self{raw: self.raw ^ right.raw} }
}
impl core::ops::Div for $name {
type Output = Self;
fn div(self, right: Self) -> Self { Self{raw: self.raw / right.raw} }
}
impl core::ops::Mul for $name {
type Output = Self;
fn mul(self, right: Self) -> Self { Self{raw: self.raw * right.raw} }
}
impl core::ops::Shl for $name {
type Output = Self;
fn shl(self, right: Self) -> Self { Self{raw: self.raw << right.raw} }
}
impl core::ops::Shr for $name {
type Output = Self;
fn shr(self, right: Self) -> Self { Self{raw: self.raw >> right.raw} }
}
impl core::ops::Sub for $name {
type Output = Self;
fn sub(self, right: Self) -> Self { Self{raw: self.raw - right.raw} }
}
impl core::ops::Rem for $name {
type Output = Self;
fn rem(self, right: Self) -> Self { Self{raw: self.raw % right.raw} }
}
impl core::ops::Not for $name {
type Output = Self;
fn not(self) -> Self { Self{raw: !self.raw} }
}
impl core::ops::Neg for $name {
type Output = Self;
fn neg(self) -> Self { Self{raw: 0 - self.raw} }
}
impl core::convert::From<$type> for $name {
fn from(right: $type) -> Self { Self{raw: right} }
}
impl core::ops::AddAssign for $name {
fn add_assign(&mut self, right: Self) { self.raw += right.raw }
}
impl core::ops::SubAssign for $name {
fn sub_assign(&mut self, right: Self) { self.raw -= right.raw }
}
impl core::ops::MulAssign for $name {
fn mul_assign(&mut self, right: Self) { self.raw *= right.raw }
}
impl core::ops::BitAndAssign for $name {
fn bitand_assign(&mut self, right: Self) { self.raw &= right.raw }
}
impl core::ops::BitOrAssign for $name {
fn bitor_assign(&mut self, right: Self) { self.raw |= right.raw }
}
impl core::ops::BitXorAssign for $name {
fn bitxor_assign(&mut self, right: Self) { self.raw ^= right.raw }
}
impl core::ops::DivAssign for $name {
fn div_assign(&mut self, right: Self) { self.raw /= right.raw }
}
impl core::ops::RemAssign for $name {
fn rem_assign(&mut self, right: Self) { self.raw %= right.raw }
}
}
}
#[macro_export]
macro_rules! encap_enum {
(
$(
$(#[$outer_comment:meta])*
$outer_vis:vis enum $name:ident : $inner_vis:vis $type:ty {
$(
$val_name:ident =
$($li:literal $(- $sub_li:literal)* $(- $li_sub_id:ident)* $(- (enum $type0:ty) $li_sub_sid:ident )*)?
$($id:ident $(- $sub_id:ident)* $(- $id_sub_li:literal)* $(- (enum $type1:ty) $id_sub_sid:ident )*)?
$((enum $type2:ty) $($sid0:ident)? $(- $sid1:ident)* $(- $($sid_sub_li:literal)* )* )*
$((-$id1:ident))?
$(| $bitor_li:literal)*
$(+ $add_li:literal)*
$(& $bitand_li:literal)*
$(^ $bitxor_li:literal)*
$(/ $div_li:literal)*
$(* $mul_li:literal)*
$(<< $shl_li:literal)*
$(>> $shr_li:literal)*
$(| $bitor_id:ident)*
$(+ $add_id:ident)*
$(& $bitand_id:ident)*
$(^ $bitxor_id:ident )*
$(/ $div_id:ident )*
$(* $mul_id:ident )*
$(<< $shl_id:ident )*
$(>> $shr_id:ident )*
$(| (enum $bitor_type_sid:ty) $bitor_sid:ident )*
$(+ (enum $add_type_sid:ty) $add_sid:ident )*
$(& (enum $bitand_type_sid:ty) $bitand_sid:ident )*
$(^ (enum $bitxor_type_sid:ty) $bitxor_sid:ident )*
$(/ (enum $div_type_sid:ty) $div_sid:ident )*
$(* (enum $mul_type_sid:ty) $mul_sid:ident )*
$(<< (enum $shl_type_sid:ty) $shl_sid:ident )*
$(>> (enum $shr_type_sid:ty) $shr_sid:ident )*
,$(#[$comment:meta])*
)+
}
)+
) => {
$(
$(#[$outer_comment])*
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Hash)]
$outer_vis struct $name{
$inner_vis raw: $type
}
__encap_enum_impl!{$name, $type}
impl $name {
$inner_vis const fn new(data: $type) -> Self{
Self{raw: data}
}
pub fn iter() -> core::slice::Iter<'static, $type> {
const _ARRAY: &[$type] = &[$($name :: $val_name .raw,)+];
_ARRAY.into_iter()
}
$inner_vis fn get_bit(&self, bit:u8) -> bool{
self.raw & (1 << bit) != 0
}
$(
$(#[$comment])*
#[allow(non_upper_case_globals)]
pub const $val_name: $name = $name { raw :
$($li $(- $sub_li)* $(- $name :: $li_sub_id .raw)* $(- $type0 :: new($li_sub_sid) .raw )*)?
$($name :: $id .raw $(- $name :: $sub_id .raw)* $(- $id_sub_li)* $(- $type1 ::new($id_sub_sid) .raw )*)?
$(<$type2> :: new($($sid0)? $(- $sid1)*) .raw $(- $($sid_sub_li)* )*)*
$(- $name :: $id1 .raw)?
$(| $bitor_li )*
$(+ $add_li )*
$(& $bitand_li )*
$(^ $bitxor_li )*
$(/ $div_li )*
$(* $mul_li )*
$(<< $shl_li )*
$(>> $shr_li )*
$(| $name :: $bitor_id .raw )*
$(+ $name :: $add_id .raw )*
$(& $name :: $bitand_id .raw )*
$(^ $name :: $bitxor_id .raw )*
$(/ $name :: $div_id .raw )*
$(* $name :: $mul_id .raw )*
$(<< $name :: $shl_id .raw )*
$(>> $name :: $shr_id .raw )*
$(| <$bitor_type_sid> :: new($bitor_sid) .raw )*
$(+ <$add_type_sid> :: new($add_sid) .raw )*
$(& <$bitand_type_sid> :: new($bitand_sid) .raw )*
$(^ <$bitxor_type_sid> :: new($bitxor_sid) .raw )*
$(/ <$div_type_sid> :: new($div_sid) .raw )*
$(* <$mul_type_sid> :: new($mul_sid) .raw )*
$(<< <$shl_type_sid> :: new($shl_sid) .raw )*
$(>> <$shr_type_sid> :: new($shr_sid) .raw )*
};
)+
}
)+
};
(
$(
$(#[$outer_comment:meta])*
$outer_vis:vis enum $name:ident {
$(
$val_name:ident =
$($li:literal $(- $sub_li:literal)* $(- $li_sub_id:ident)* $(- (enum $type0:ty) $li_sub_sid:ident )*)?
$($id:ident $(- $sub_id:ident)* $(- $id_sub_li:literal)* $(- (enum $type1:ty) $id_sub_sid:ident )*)?
$((enum $type2:ty) $($sid0:ident)? $(- $sid1:ident)* $(- $($sid_sub_li:literal)* )* )*
$((-$id1:ident))?
$(| $bitor_li:literal)*
$(+ $add_li:literal)*
$(& $bitand_li:literal)*
$(^ $bitxor_li:literal)*
$(/ $div_li:literal)*
$(* $mul_li:literal)*
$(<< $shl_li:literal)*
$(>> $shr_li:literal)*
$(| $bitor_id:ident)*
$(+ $add_id:ident)*
$(& $bitand_id:ident)*
$(^ $bitxor_id:ident )*
$(/ $div_id:ident )*
$(* $mul_id:ident )*
$(<< $shl_id:ident )*
$(>> $shr_id:ident )*
$(| (enum $bitor_type_sid:ty) $bitor_sid:ident )*
$(+ (enum $add_type_sid:ty) $add_sid:ident )*
$(& (enum $bitand_type_sid:ty) $bitand_sid:ident )*
$(^ (enum $bitxor_type_sid:ty) $bitxor_sid:ident )*
$(/ (enum $div_type_sid:ty) $div_sid:ident )*
$(* (enum $mul_type_sid:ty) $mul_sid:ident )*
$(<< (enum $shl_type_sid:ty) $shl_sid:ident )*
$(>> (enum $shr_type_sid:ty) $shr_sid:ident )*
,$(#[$comment:meta])*
)+
}
)+
) => {
$(
$(#[$outer_comment])?
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Hash)]
$outer_vis struct $name{
raw: isize
}
__encap_enum_impl!{$name, isize}
impl $name {
const fn new(data: isize) -> Self{
Self{raw: data}
}
pub fn iter() -> core::slice::Iter<'static, isize> {
const _ARRAY: &[isize] = &[$($name :: $val_name .raw,)+];
_ARRAY.into_iter()
}
$(
$(#[$comment])*
#[allow(non_upper_case_globals)]
pub const $val_name: $name = $name { raw :
$($li $(- $sub_li)* $(- $name :: $li_sub_id .raw)* $(- $type0 ($li_sub_sid) .raw )*)?
$($name :: $id .raw $(- $name :: $sub_id .raw)* $(- $id_sub_li)* $(- $type1 ($id_sub_sid) .raw )*)?
$($type2 ($($sid0)? $(- $sid1)*) .raw $(- $($sid_sub_li)* )*)*
$(- $name :: $id1 .raw)?
$(| $bitor_li )*
$(+ $add_li )*
$(& $bitand_li )*
$(^ $bitxor_li )*
$(/ $div_li )*
$(* $mul_li )*
$(<< $shl_li )*
$(>> $shr_li )*
$(| $name :: $bitor_id .raw )*
$(+ $name :: $add_id .raw )*
$(& $name :: $bitand_id .raw )*
$(^ $name :: $bitxor_id .raw )*
$(/ $name :: $div_id .raw )*
$(* $name :: $mul_id .raw )*
$(<< $name :: $shl_id .raw )*
$(>> $name :: $shr_id .raw )*
$(| <$bitor_type_sid> :: new($bitor_sid) .raw )*
$(+ <$add_type_sid> :: new($add_sid) .raw )*
$(& <$bitand_type_sid> :: new($bitand_sid) .raw )*
$(^ <$bitxor_type_sid> :: new($bitxor_sid) .raw )*
$(/ <$div_type_sid> :: new($div_sid) .raw )*
$(* <$mul_type_sid> :: new($mul_sid) .raw )*
$(<< <$shl_type_sid> :: new($shl_sid) .raw )*
$(>> <$shr_type_sid> :: new($shr_sid) .raw )*
};
)+
}
)+
};
(
$(#[$outermost_comment:meta])*
$whole_vis:vis mod $namespace:ident {
$(
$(#[$outer_comment:meta])*
$outer_vis:vis enum $name:ident {
$($val_name:ident,$(#[$comment:meta])*)+
}
)+
}
) => {
$(#[$outermost_comment])*
#[allow(non_camel_case_types)]
$whole_vis mod $namespace {
mod __encap_enum {
$(
#[allow(non_snake_case)]
pub mod $name {
pub enum $namespace {
$($val_name,)+
}
}
)+
}
$(
$(#[$outer_comment])*
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Hash)]
$outer_vis struct $name{
raw: isize
}
__encap_enum_impl!{$name, isize}
impl $name {
pub fn iter() -> core::slice::Iter<'static, isize> {
const _ARRAY: &[isize] = &[$($name :: $val_name .raw,)+];
_ARRAY.into_iter()
}
$(
$(#[$comment])*
#[allow(non_upper_case_globals)]
pub const $val_name: $name = $name { raw : __encap_enum :: $name:: $namespace :: $val_name as isize};
)+
}
)+
}
};
(
$(#[$outermost_comment:meta])*
$whole_vis:vis mod $namespace:ident {
$(
$(#[$outer_comment:meta])*
$outer_vis:vis enum $name:ident : $inner_vis:vis $type:ty{
$($val_name:ident,$(#[$comment:meta])*)+
}
)+
}
) => {
$(#[$outermost_comment])*
#[allow(non_camel_case_types)]
$whole_vis mod $namespace {
mod __encap_enum {
$(
#[allow(non_snake_case)]
pub mod $name {
pub enum $namespace {
$($val_name,)+
}
}
)+
}
$(
$(#[$outer_comment])*
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Hash)]
$outer_vis struct $name{
$inner_vis raw: $type
}
__encap_enum_impl!{$name, $type}
impl $name {
$inner_vis const fn new(data: $type) -> Self{
Self{raw: data}
}
pub fn iter() -> core::slice::Iter<'static, $type> {
const _ARRAY: &[$type] = &[$($name :: $val_name .raw,)+];
_ARRAY.into_iter()
}
$inner_vis fn get_bit(&self, bit:u8) -> bool{
self.raw & (1 << bit) != 0
}
$(
$(#[$comment])*
#[allow(non_upper_case_globals)]
pub const $val_name: $name = $name { raw : __encap_enum :: $name:: $namespace :: $val_name as $type};
)+
}
)+
}
};
(
$(
$(#[$outer_comment:meta])*
$outer_vis:vis enum $name:ident : $inner_vis:vis $type:ty{
$($val_name:ident,$(#[$comment:meta])*)+
}
)+
) => { compile_error!("encap_enum requires fieldless enums to be under a 'mod'.")}
}
#[cfg(test)]
mod tests {
encap_enum!(
pub mod flag {
pub enum TestEnum: pub isize {
Array,
Bar,
Jar,
Foo,
}
}
);
encap_enum!{
mod m0 {
enum MultEnum0 {
A,
B,
C,
}
}
}
encap_enum!{
mod m1 {
enum MultEnum0: u32 {
A,
B,
C,
}
enum m1: u32 {
A,
B,
C,
}
}
}
encap_enum!{
enum OtherEnum{
Foo = 0,
Bar = 1,
Rust = 2,
}
enum DuplicateEnum{
Foo = 0,
Bar = 1,
Rust = 2,
}
}
encap_enum!{
enum SpecificEnum: pub u32{
Foo = 0,
Bar = 1,
Rust = 2,
}
}
encap_enum!{
enum SignedEnum: pub i32 {
Food = 1 - 3,
Bard = (-Food) * 3,
Jard = -3,
Read = Jard - Bard,
Yard = (enum SignedEnum) TEST_CONST - (enum SignedEnum) TEST_CONST_TWO,
}
}
encap_enum! {
mod test_flag {
enum test_flag: u32 {
A, B, C,
}
enum thing2: u32 {
G, H, J, K,
}
}
}
const TEST_CONST: i32 = 64;
const TEST_CONST_TWO: i32 = 57;
#[test]
fn value_integrity() {
let var0 = flag::TestEnum::Array;
let var1 = flag::TestEnum::Bar | flag::TestEnum::Jar;
assert_eq!(-OtherEnum::Bar.raw, -1); assert_eq!(var0.raw, 0);
assert_eq!(var1.raw, 3);
assert_eq!(SignedEnum::Bard, 6.into());
assert_eq!(SignedEnum::Yard.raw, TEST_CONST - TEST_CONST_TWO);
assert_eq!(SignedEnum::Bard.get_bit(1), true);
}
#[test]
fn into_from() {
let var: flag::TestEnum = flag::TestEnum::from(54);
assert_eq!(var, 54.into());
}
#[test]
fn iteration() {
encap_enum!{
pub mod tmp {
pub enum GreaterEnum: pub u32{
Bar,
Foo,
Rust,
}
}
}
assert_ne!(tmp::GreaterEnum::Bar.raw as isize, flag::TestEnum::Bar.raw);
let mut count = 0isize;
for t in flag::TestEnum::iter() {
assert_eq!(&count, t);
count += 1;
}
count = 0;
for t in OtherEnum::iter() {
assert_eq!(&count, t);
count += 1;
}
let mut count = 0u32;
for t in SpecificEnum::iter() {
assert_eq!(&count, t);
count += 1;
}
count = 0;
for t in tmp::GreaterEnum::iter() {
assert_eq!(&count, t);
count += 1;
}
}
#[test]
fn enumeration() {
let mut count = 0;
#[allow(clippy::explicit_counter_loop)]
for (t, _y) in flag::TestEnum::iter().enumerate() {
assert_eq!(count, t);
count += 1;
}
}
#[test]
fn assignment() {
encap_enum!{
pub mod thing {
pub enum GreaterEnum: pub u32{
Bar,
Foo,
Rust,
}
}
}
let a = flag::TestEnum::Array;
let mut b = flag::TestEnum::Bar;
b += a;
b -= a;
b *= a;
b &= a;
b |= a;
b /= 54.into();
b ^= 6.into();
b %= 30.into();
let t = OtherEnum::Rust;
let mut z = OtherEnum::Foo;
z += t;
z -= t;
z *= t;
z &= t;
z |= t;
z /= t;
z ^= t;
z %= t;
let t = SpecificEnum::Rust;
let mut z = SpecificEnum::Foo;
z += t;
z -= t;
z *= t;
z &= t;
z |= t;
z /= t;
z ^= t;
z %= t;
let t = thing::GreaterEnum::Rust;
let mut z = thing::GreaterEnum::Foo;
z += t;
z -= t;
z *= thing::GreaterEnum::Bar;
z &= t;
z |= t;
z /= t;
z ^= t;
z %= t;
}
#[test]
fn externvar(){
const AQUA: u32 = 34;
const TERA: u32 = 64;
encap_enum!{
enum ExternEnum: u32{
Aqua = (enum ExternEnum)AQUA + (enum ExternEnum)TERA,
}
}
assert_eq!(ExternEnum::Aqua.raw, AQUA + TERA);
}
}