Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an "impl_arbitrary" feature to enable implementing Arbitrary. #260

Closed
wants to merge 12 commits into from
2 changes: 1 addition & 1 deletion .github/workflows/rust.yml
Expand Up @@ -32,7 +32,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: test
args: --features example_generated
args: --features example_generated,impl_arbitrary
sunfishcode marked this conversation as resolved.
Show resolved Hide resolved

embedded:
name: Build (embedded)
Expand Down
4 changes: 3 additions & 1 deletion Cargo.toml
Expand Up @@ -21,6 +21,7 @@ exclude = ["bors.toml"]
[dependencies]
core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' }
compiler_builtins = { version = '0.1.2', optional = true }
arbitrary = { version = "1", optional = true }

[dev-dependencies]
trybuild = "1.0"
Expand All @@ -29,10 +30,11 @@ walkdir = "2.3"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
arbitrary = "1"
sunfishcode marked this conversation as resolved.
Show resolved Hide resolved

[features]
default = []
example_generated = []
example_generated = ["arbitrary"]
rustc-dep-of-std = ["core", "compiler_builtins"]

[package.metadata.docs.rs]
Expand Down
5 changes: 5 additions & 0 deletions README.md
Expand Up @@ -27,6 +27,11 @@ and this to your source code:
use bitflags::bitflags;
```

Enable the `arbitrary` feature to enable implementations of the [`Arbitrary`]
trait for the generated structures.

[`Arbitrary`]: https://docs.rs/arbitrary/1.0.1/arbitrary/trait.Arbitrary.html

## Rust Version Support

The minimum supported Rust version is 1.46 due to use of associated constants and const functions.
32 changes: 32 additions & 0 deletions src/lib.rs
Expand Up @@ -820,6 +820,8 @@ macro_rules! __impl_bitflags {
result
}
}

__impl_arbitrary_for_bitflags!($BitFlags);
};

// Every attribute that the user writes on a const is applied to the
Expand Down Expand Up @@ -931,6 +933,36 @@ macro_rules! __impl_bitflags {
};
}

// When "arbitrary" is enabled, emit code to implement the `Arbitrary` trait.
#[cfg(feature = "arbitrary")]
#[macro_export]
#[doc(hidden)]
macro_rules! __impl_arbitrary_for_bitflags {
($BitFlags:ident) => {
impl<'a> $crate::_arbitrary::Arbitrary<'a> for $BitFlags {
fn arbitrary(
u: &mut $crate::_arbitrary::Unstructured<'a>
) -> $crate::_arbitrary::Result<Self> {
Self::from_bits(u.arbitrary()?).ok_or_else(|| $crate::_arbitrary::Error::IncorrectFormat)
}
}
};
}

// When "arbitrary" is not enabled, don't emit any code for it.
#[cfg(not(feature = "arbitrary"))]
#[macro_export]
#[doc(hidden)]
macro_rules! __impl_arbitrary_for_bitflags {
($BitFlags:ident) => {};
}

// Re-export `arbitrary` so that our macro expansions can refer to it by a
// known name.
#[cfg(feature = "arbitrary")]
#[doc(hidden)]
pub extern crate arbitrary as _arbitrary;

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

Expand Down
17 changes: 17 additions & 0 deletions tests/arbitrary.rs
@@ -0,0 +1,17 @@
#![cfg(feature = "arbitrary")]

use arbitrary::Arbitrary;

bitflags::bitflags! {
struct Color: u32 {
const RED = 0x1;
const GREEN = 0x2;
const BLUE = 0x4;
}
}

#[test]
fn test_arbitary() {
let mut unstructured = arbitrary::Unstructured::new(&[0_u8; 256]);
let _color = Color::arbitrary(&mut unstructured);
}
20 changes: 20 additions & 0 deletions tests/compile-pass/redefinition/arbitrary.rs
@@ -0,0 +1,20 @@
use bitflags::bitflags;

// Checks for possible errors caused by overriding names used by `bitflags!` internally.

mod arbitrary {}
mod _arbitrary {}

bitflags! {
struct Test: u8 {
const A = 1;
}
}

fn main() {
#[cfg(feature = "arbitrary")]
{
let mut unstructured = arbitrary::Unstructured::new(&[0_u8; 256]);
let _test = Test::arbitrary(&mut unstructured);
}
}