Skip to content

Commit

Permalink
Merge pull request #286 from KodrAus/feat/bitflags-trait-iter
Browse files Browse the repository at this point in the history
expose bitflags iters using nameable types
  • Loading branch information
KodrAus committed Oct 6, 2022
2 parents 07af9c4 + 62352c8 commit 87e859b
Show file tree
Hide file tree
Showing 10 changed files with 1,182 additions and 912 deletions.
42 changes: 18 additions & 24 deletions src/example_generated.rs
@@ -1,43 +1,37 @@
//! This module shows an example of code generated by the macro. **IT MUST NOT BE USED OUTSIDE THIS
//! CRATE**.
//!
//! Usually, when you call the `bitflags!` macro, only the `Flags` type would be visible. In this
//! example, the `Field0`, `Iter`, and `IterRaw` types are also exposed so that you can explore
//! their APIs. The `Field0` type can be accessed as `self.0` on an instance of `Flags`.

bitflags! {
__declare_public_bitflags! {
/// This is the same `Flags` struct defined in the [crate level example](../index.html#example).
/// Note that this struct is just for documentation purposes only, it must not be used outside
/// this crate.
pub struct Flags: u32 {
const A = 0b00000001;
const B = 0b00000010;
const C = 0b00000100;
const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits();
}
pub struct Flags;
}

/// This is the same internal field available as `self.0` on bitflags types.
/// These types aren't reachable by callers of `bitflags!`, they don't appear in the API of your
/// crate, but you can still interact with them through `self.0` in the module that defines the
/// bitflags type.
///
/// You can use this example as a reference for what methods are available to all internal bitflags
/// fields if you want to add custom functionality to your bitflags types.
///
/// Note that this struct is just for documentation purposes only, it must not be used outside
/// this crate.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct FlagsField {
bits: u32,
__declare_internal_bitflags! {
pub struct Field0: u32;
pub struct Iter;
pub struct IterRaw;
}

__impl_internal_bitflags! {
FlagsField: u32 {
Field0: u32, Flags, Iter, IterRaw {
A;
B;
C;
ABC;
}
}

impl crate::__private::InternalFlags for FlagsField {
type PublicFlags = Flags;
__impl_public_bitflags! {
Flags: u32, Field0, Iter, IterRaw {
A = 0b00000001;
B = 0b00000010;
C = 0b00000100;
ABC = Self::A.bits() | Self::B.bits() | Self::C.bits();
}
}
88 changes: 88 additions & 0 deletions src/external.rs
@@ -0,0 +1,88 @@
//! Conditional trait implementations for external libraries.

#[cfg(feature = "serde")]
pub mod serde_support;

/// Implements traits from external libraries for the internal bitflags type.
#[macro_export(local_inner_macros)]
#[doc(hidden)]
macro_rules! __impl_external_bitflags {
(
$InternalBitFlags:ident: $T:ty {
$(
$(#[$attr:ident $($args:tt)*])*
$Flag:ident;
)*
}
) => {
// Any new library traits impls should be added here
// Use `serde` as an example: generate code when the feature is available,
// and a no-op when it isn't

__impl_external_bitflags_serde! {
$InternalBitFlags: $T {
$(
$(#[$attr $($args)*])*
$Flag;
)*
}
}
};
}

/// Implement `Serialize` and `Deserialize` for the internal bitflags type.
#[macro_export(local_inner_macros)]
#[doc(hidden)]
#[cfg(feature = "serde")]
macro_rules! __impl_external_bitflags_serde {
(
$InternalBitFlags:ident: $T:ty {
$(
$(#[$attr:ident $($args:tt)*])*
$Flag:ident;
)*
}
) => {
impl $crate::__private::serde::Serialize for $InternalBitFlags {
fn serialize<S: $crate::__private::serde::Serializer>(
&self,
serializer: S,
) -> $crate::__private::core::result::Result<S::Ok, S::Error> {
$crate::__private::serde_support::serialize_bits_default(
$crate::__private::core::stringify!($InternalBitFlags),
&self.bits,
serializer,
)
}
}

impl<'de> $crate::__private::serde::Deserialize<'de> for $InternalBitFlags {
fn deserialize<D: $crate::__private::serde::Deserializer<'de>>(
deserializer: D,
) -> $crate::__private::core::result::Result<Self, D::Error> {
let bits = $crate::__private::serde_support::deserialize_bits_default(
$crate::__private::core::stringify!($InternalBitFlags),
deserializer,
)?;

$crate::__private::core::result::Result::Ok($InternalBitFlags::from_bits_retain(
bits,
))
}
}
};
}

#[macro_export(local_inner_macros)]
#[doc(hidden)]
#[cfg(not(feature = "serde"))]
macro_rules! __impl_external_bitflags_serde {
(
$InternalBitFlags:ident: $T:ty {
$(
$(#[$attr:ident $($args:tt)*])*
$Flag:ident;
)*
}
) => {};
}
21 changes: 16 additions & 5 deletions src/serde_support.rs → src/external/serde_support.rs
@@ -1,15 +1,26 @@
use core::fmt;
use serde::{Serializer, Deserializer, Serialize, Deserialize, ser::SerializeStruct, de::{Error, MapAccess, Visitor}};
use serde::{
de::{Error, MapAccess, Visitor},
ser::SerializeStruct,
Deserialize, Deserializer, Serialize, Serializer,
};

// These methods are compatible with the result of `#[derive(Serialize, Deserialize)]` on bitflags `1.0` types

pub fn serialize_bits_default<B: Serialize, S: Serializer>(name: &'static str, bits: &B, serializer: S) -> Result<S::Ok, S::Error> {
pub fn serialize_bits_default<B: Serialize, S: Serializer>(
name: &'static str,
bits: &B,
serializer: S,
) -> Result<S::Ok, S::Error> {
let mut serialize_struct = serializer.serialize_struct(name, 1)?;
serialize_struct.serialize_field("bits", bits)?;
serialize_struct.end()
}

pub fn deserialize_bits_default<'de, B: Deserialize<'de>, D: Deserializer<'de>>(name: &'static str, deserializer: D) -> Result<B, D::Error> {
pub fn deserialize_bits_default<'de, B: Deserialize<'de>, D: Deserializer<'de>>(
name: &'static str,
deserializer: D,
) -> Result<B, D::Error> {
struct BitsVisitor<T>(core::marker::PhantomData<T>);

impl<'de, T: Deserialize<'de>> Visitor<'de> for BitsVisitor<T> {
Expand All @@ -31,7 +42,7 @@ pub fn deserialize_bits_default<'de, B: Deserialize<'de>, D: Deserializer<'de>>(

bits = Some(map.next_value()?);
}
v => return Err(Error::unknown_field(v, &["bits"]))
v => return Err(Error::unknown_field(v, &["bits"])),
}
}

Expand Down Expand Up @@ -81,4 +92,4 @@ mod tests {

assert_eq!(deserialized.bits(), flags.bits());
}
}
}

0 comments on commit 87e859b

Please sign in to comment.