Skip to content

Commit

Permalink
Merge pull request #17 from DCNick3/full-trait-method-reference
Browse files Browse the repository at this point in the history
Refer to trait methods by their fully qualified names
  • Loading branch information
Lukas3674 authored Feb 27, 2024
2 parents 4e6901d + 51410d9 commit 29843a8
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 48 deletions.
72 changes: 40 additions & 32 deletions src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
use proc_macro::{Span, TokenStream};
use syn::{
Error, Result,
Ident, ItemEnum, Token,
parse::{Parse, ParseStream},
punctuated::Punctuated,
Error, Ident, ItemEnum, Result, Token,
};

pub fn parse(attr: TokenStream, mut item: ItemEnum) -> Result<TokenStream> {
let typ = parse_typ(attr)?;

let config = if let Some(idx) = item.attrs.iter().enumerate().find_map(
|(idx, attr)| attr.path().is_ident("bitmask_config").then_some(idx)
) {
let config = if let Some(idx) = item
.attrs
.iter()
.enumerate()
.find_map(|(idx, attr)| attr.path().is_ident("bitmask_config").then_some(idx))
{
item.attrs.remove(idx).parse_args::<Config>()?
} else {
Config::new()
Expand Down Expand Up @@ -47,17 +49,20 @@ pub fn parse(attr: TokenStream, mut item: ItemEnum) -> Result<TokenStream> {
expr
};

let i_flag = config.inverted_flags.then(|| {
let i_ident = Ident::new(&format!("Inverted{}", v_ident), v_ident.span());
let i_flag = config
.inverted_flags
.then(|| {
let i_ident = Ident::new(&format!("Inverted{}", v_ident), v_ident.span());

all_flags.push(quote::quote!(Self::#i_ident));
all_flags_names.push(quote::quote!(stringify!(#i_ident)));
all_flags.push(quote::quote!(Self::#i_ident));
all_flags_names.push(quote::quote!(stringify!(#i_ident)));

quote::quote!(
#(#v_attrs)*
#vis const #i_ident: #ident = Self { bits: (#expr) ^ !0 };
)
}).into_iter();
quote::quote!(
#(#v_attrs)*
#vis const #i_ident: #ident = Self { bits: (#expr) ^ !0 };
)
})
.into_iter();

flags.push(quote::quote!(
#(#v_attrs)*
Expand All @@ -81,7 +86,7 @@ pub fn parse(attr: TokenStream, mut item: ItemEnum) -> Result<TokenStream> {
}
}
}
} else {
} else {
quote::quote! {
impl core::fmt::Debug for #ident {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
Expand Down Expand Up @@ -208,52 +213,52 @@ pub fn parse(attr: TokenStream, mut item: ItemEnum) -> Result<TokenStream> {
type Output = Self;
#[inline]
fn not(self) -> Self::Output {
Self { bits: self.bits.not() }
Self { bits: core::ops::Not::not(self.bits) }
}
}

impl core::ops::BitAnd for #ident {
type Output = Self;
#[inline]
fn bitand(self, rhs: Self) -> Self::Output {
Self { bits: self.bits.bitand(rhs.bits) }
Self { bits: core::ops::BitAnd::bitand(self.bits, rhs.bits) }
}
}

impl core::ops::BitAndAssign for #ident {
#[inline]
fn bitand_assign(&mut self, rhs: Self){
self.bits.bitand_assign(rhs.bits)
fn bitand_assign(&mut self, rhs: Self) {
core::ops::BitAndAssign::bitand_assign(&mut self.bits, rhs.bits)
}
}

impl core::ops::BitOr for #ident {
type Output = Self;
#[inline]
fn bitor(self, rhs: Self) -> Self::Output {
Self { bits: self.bits.bitor(rhs.bits) }
Self { bits: core::ops::BitOr::bitor(self.bits, rhs.bits) }
}
}

impl core::ops::BitOrAssign for #ident {
#[inline]
fn bitor_assign(&mut self, rhs: Self){
self.bits.bitor_assign(rhs.bits)
fn bitor_assign(&mut self, rhs: Self) {
core::ops::BitOrAssign::bitor_assign(&mut self.bits, rhs.bits)
}
}

impl core::ops::BitXor for #ident {
type Output = Self;
#[inline]
fn bitxor(self, rhs: Self) -> Self::Output {
Self { bits: self.bits.bitxor(rhs.bits) }
Self { bits: core::ops::BitXor::bitxor(self.bits, rhs.bits) }
}
}

impl core::ops::BitXorAssign for #ident {
#[inline]
fn bitxor_assign(&mut self, rhs: Self){
self.bits.bitxor_assign(rhs.bits)
fn bitxor_assign(&mut self, rhs: Self) {
core::ops::BitXorAssign::bitxor_assign(&mut self.bits, rhs.bits)
}
}

Expand Down Expand Up @@ -283,28 +288,28 @@ pub fn parse(attr: TokenStream, mut item: ItemEnum) -> Result<TokenStream> {
impl core::fmt::Binary for #ident {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.bits.fmt(f)
core::fmt::Binary::fmt(&self.bits, f)
}
}

impl core::fmt::LowerHex for #ident {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.bits.fmt(f)
core::fmt::LowerHex::fmt(&self.bits, f)
}
}

impl core::fmt::UpperHex for #ident {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.bits.fmt(f)
core::fmt::UpperHex::fmt(&self.bits, f)
}
}

impl core::fmt::Octal for #ident {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.bits.fmt(f)
core::fmt::Octal::fmt(&self.bits, f)
}
}
}))
Expand All @@ -319,21 +324,24 @@ fn parse_typ(attr: TokenStream) -> Result<Ident> {
#[rustfmt::skip]
"u8" | "u16" | "u32" | "u64" | "u128" | "usize" |
"i8" | "i16" | "i32" | "i64" | "i128" | "isize" => Ok(ident),
_ => Err(Error::new_spanned(ident, "type can only be an (un)signed integer")),
_ => Err(Error::new_spanned(
ident,
"type can only be an (un)signed integer",
)),
}
}
}

struct Config {
inverted_flags: bool,
vec_debug: bool
vec_debug: bool,
}

impl Config {
fn new() -> Self {
Self {
inverted_flags: false,
vec_debug: false
vec_debug: false,
}
}
}
Expand Down
98 changes: 82 additions & 16 deletions tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,17 @@ mod tests {
fn test_full() {
let full = Bitmask::full();
assert_eq!(full.is_full(), true);
assert_eq!(full, Bitmask::Flag1 | Bitmask::Flag2 | Bitmask::Flag3 | Bitmask::Flag4 | Bitmask::Flag5 | Bitmask::Flag6 | Bitmask::Flag7 | Bitmask::Flag8);
assert_eq!(
full,
Bitmask::Flag1
| Bitmask::Flag2
| Bitmask::Flag3
| Bitmask::Flag4
| Bitmask::Flag5
| Bitmask::Flag6
| Bitmask::Flag7
| Bitmask::Flag8
);
}

#[test]
Expand Down Expand Up @@ -347,19 +357,43 @@ mod tests {
Flag3,
}

assert_eq!(format!("{:?}", BitmaskVecDebug::none()), "BitmaskVecDebug[]");
assert_eq!(format!("{:?}", BitmaskVecDebug::Flag1), "BitmaskVecDebug[Flag1]");
assert_eq!(format!("{:?}", BitmaskVecDebug::Flag2), "BitmaskVecDebug[Flag2]");
assert_eq!(format!("{:?}", BitmaskVecDebug::Flag12), "BitmaskVecDebug[Flag1, Flag2, Flag12]");
assert_eq!(format!("{:?}", BitmaskVecDebug::Flag3), "BitmaskVecDebug[Flag3]");
assert_eq!(format!("{:?}", BitmaskVecDebug::Flag2.or(BitmaskVecDebug::Flag3)), "BitmaskVecDebug[Flag2, Flag3]");
assert_eq!(format!("{:?}", BitmaskVecDebug::full()), "BitmaskVecDebug[Flag1, Flag2, Flag12, Flag3]");
assert_eq!(
format!("{:?}", BitmaskVecDebug::none()),
"BitmaskVecDebug[]"
);
assert_eq!(
format!("{:?}", BitmaskVecDebug::Flag1),
"BitmaskVecDebug[Flag1]"
);
assert_eq!(
format!("{:?}", BitmaskVecDebug::Flag2),
"BitmaskVecDebug[Flag2]"
);
assert_eq!(
format!("{:?}", BitmaskVecDebug::Flag12),
"BitmaskVecDebug[Flag1, Flag2, Flag12]"
);
assert_eq!(
format!("{:?}", BitmaskVecDebug::Flag3),
"BitmaskVecDebug[Flag3]"
);
assert_eq!(
format!("{:?}", BitmaskVecDebug::Flag2.or(BitmaskVecDebug::Flag3)),
"BitmaskVecDebug[Flag2, Flag3]"
);
assert_eq!(
format!("{:?}", BitmaskVecDebug::full()),
"BitmaskVecDebug[Flag1, Flag2, Flag12, Flag3]"
);

// default formatting
assert_eq!(format!("{:?}", Bitmask::none()), "Bitmask { bits: 0 }");
assert_eq!(format!("{:?}", Bitmask::Flag1), "Bitmask { bits: 1 }");
assert_eq!(format!("{:?}", Bitmask::Flag2), "Bitmask { bits: 2 }");
assert_eq!(format!("{:?}", Bitmask::Flag1.or(Bitmask::Flag2)), "Bitmask { bits: 3 }");
assert_eq!(
format!("{:?}", Bitmask::Flag1.or(Bitmask::Flag2)),
"Bitmask { bits: 3 }"
);
assert_eq!(format!("{:?}", Bitmask::Flag3), "Bitmask { bits: 4 }");
}

Expand All @@ -369,14 +403,46 @@ mod tests {
#[bitmask_config(vec_debug, inverted_flags)]
pub enum BitmaskVecDebug {
Flag1,
Flag2
Flag2,
}

assert_eq!(format!("{:?}", BitmaskVecDebug::none()), "BitmaskVecDebug[]");
assert_eq!(format!("{:?}", BitmaskVecDebug::Flag1), "BitmaskVecDebug[Flag1]");
assert_eq!(format!("{:?}", BitmaskVecDebug::Flag2), "BitmaskVecDebug[Flag2]");
assert_eq!(format!("{:?}", BitmaskVecDebug::InvertedFlag1), "BitmaskVecDebug[InvertedFlag1, Flag2]");
assert_eq!(format!("{:?}", BitmaskVecDebug::InvertedFlag2), "BitmaskVecDebug[Flag1, InvertedFlag2]");
assert_eq!(format!("{:?}", BitmaskVecDebug::full()), "BitmaskVecDebug[Flag1, InvertedFlag1, Flag2, InvertedFlag2]");
assert_eq!(
format!("{:?}", BitmaskVecDebug::none()),
"BitmaskVecDebug[]"
);
assert_eq!(
format!("{:?}", BitmaskVecDebug::Flag1),
"BitmaskVecDebug[Flag1]"
);
assert_eq!(
format!("{:?}", BitmaskVecDebug::Flag2),
"BitmaskVecDebug[Flag2]"
);
assert_eq!(
format!("{:?}", BitmaskVecDebug::InvertedFlag1),
"BitmaskVecDebug[InvertedFlag1, Flag2]"
);
assert_eq!(
format!("{:?}", BitmaskVecDebug::InvertedFlag2),
"BitmaskVecDebug[Flag1, InvertedFlag2]"
);
assert_eq!(
format!("{:?}", BitmaskVecDebug::full()),
"BitmaskVecDebug[Flag1, InvertedFlag1, Flag2, InvertedFlag2]"
);
}

#[test]
fn test_import_debug() {
// check that having a `Debug` import doesn't lead to a conflict
#[allow(unused)]
use std::fmt::Debug;

// this should just compile
#[bitmask]
pub enum BitmaskImportDebug {
Flag1,
Flag2,
}
}
}

0 comments on commit 29843a8

Please sign in to comment.