aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Maurer <mmaurer@google.com>2023-04-04 12:12:01 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-04-04 12:12:01 +0000
commitcb3f07245160fece9ab00552829234000b5fe661 (patch)
tree71072e4f3b2bd823a6e356c31736bc837a2e6622
parentfa8e13476a446bc339a57cd590440d572f995746 (diff)
parent735c0d0505a9097967f38eb3e235a2713429a95d (diff)
downloadderive_arbitrary-cb3f07245160fece9ab00552829234000b5fe661.tar.gz
Upgrade derive_arbitrary to 1.3.0 am: bd22a34ae7 am: 81a681e628 am: 735c0d0505android14-dev
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/derive_arbitrary/+/2520840 Change-Id: Ib3a2987f6a7bc78f37e761859fdbb5161674c390 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--Android.bp2
-rw-r--r--Cargo.toml9
-rw-r--r--Cargo.toml.orig4
-rw-r--r--METADATA8
-rw-r--r--src/container_attributes.rs72
-rw-r--r--src/field_attributes.rs4
-rw-r--r--src/lib.rs59
8 files changed, 144 insertions, 16 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 1f38b6d..5db9271 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
{
"git": {
- "sha1": "98044ba8b0f7d730b500fa3b4f2e96a5edcd926d"
+ "sha1": "c20a95029145c0eab249416f3d301c4bd21f33f6"
},
"path_in_vcs": "derive"
} \ No newline at end of file
diff --git a/Android.bp b/Android.bp
index f252be6..20506a1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -43,7 +43,7 @@ rust_proc_macro {
name: "libderive_arbitrary",
crate_name: "derive_arbitrary",
cargo_env_compat: true,
- cargo_pkg_version: "1.2.3",
+ cargo_pkg_version: "1.3.0",
srcs: ["src/lib.rs"],
edition: "2021",
rustlibs: [
diff --git a/Cargo.toml b/Cargo.toml
index 977aa61..fc076e8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
edition = "2021"
rust-version = "1.63.0"
name = "derive_arbitrary"
-version = "1.2.3"
+version = "1.3.0"
authors = [
"The Rust-Fuzz Project Developers",
"Nick Fitzgerald <fitzgen@gmail.com>",
@@ -45,5 +45,8 @@ version = "1.0"
version = "1.0"
[dependencies.syn]
-version = "1.0"
-features = ["derive"]
+version = "1.0.56"
+features = [
+ "derive",
+ "parsing",
+]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 99f5538..570519f 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
[package]
name = "derive_arbitrary"
-version = "1.2.3" # Make sure it matches the version of the arbitrary crate itself (not including the patch version)
+version = "1.3.0" # Make sure it matches the version of the arbitrary crate itself (not including the patch version)
authors = [
"The Rust-Fuzz Project Developers",
"Nick Fitzgerald <fitzgen@gmail.com>",
@@ -21,7 +21,7 @@ rust-version = "1.63.0"
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
-syn = { version = "1.0", features = ['derive'] }
+syn = { version = "1.0.56", features = ['derive', 'parsing'] }
[lib]
proc_macro = true
diff --git a/METADATA b/METADATA
index b987604..c7c7071 100644
--- a/METADATA
+++ b/METADATA
@@ -11,13 +11,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/derive_arbitrary/derive_arbitrary-1.2.3.crate"
+ value: "https://static.crates.io/crates/derive_arbitrary/derive_arbitrary-1.3.0.crate"
}
- version: "1.2.3"
+ version: "1.3.0"
license_type: NOTICE
last_upgrade_date {
year: 2023
- month: 2
- day: 1
+ month: 4
+ day: 3
}
}
diff --git a/src/container_attributes.rs b/src/container_attributes.rs
new file mode 100644
index 0000000..9a91ac8
--- /dev/null
+++ b/src/container_attributes.rs
@@ -0,0 +1,72 @@
+use crate::ARBITRARY_ATTRIBUTE_NAME;
+use syn::{
+ parse::Error, punctuated::Punctuated, DeriveInput, Lit, Meta, MetaNameValue, NestedMeta, Token,
+ TypeParam,
+};
+
+pub struct ContainerAttributes {
+ /// Specify type bounds to be applied to the derived `Arbitrary` implementation instead of the
+ /// default inferred bounds.
+ ///
+ /// ```ignore
+ /// #[arbitrary(bound = "T: Default, U: Debug")]
+ /// ```
+ ///
+ /// Multiple attributes will be combined as long as they don't conflict, e.g.
+ ///
+ /// ```ignore
+ /// #[arbitrary(bound = "T: Default")]
+ /// #[arbitrary(bound = "U: Default")]
+ /// ```
+ pub bounds: Option<Vec<Punctuated<TypeParam, Token![,]>>>,
+}
+
+impl ContainerAttributes {
+ pub fn from_derive_input(derive_input: &DeriveInput) -> Result<Self, Error> {
+ let mut bounds = None;
+
+ for attr in &derive_input.attrs {
+ if !attr.path.is_ident(ARBITRARY_ATTRIBUTE_NAME) {
+ continue;
+ }
+
+ let meta_list = match attr.parse_meta()? {
+ Meta::List(l) => l,
+ _ => {
+ return Err(Error::new_spanned(
+ attr,
+ format!(
+ "invalid `{}` attribute. expected list",
+ ARBITRARY_ATTRIBUTE_NAME
+ ),
+ ))
+ }
+ };
+
+ for nested_meta in meta_list.nested.iter() {
+ match nested_meta {
+ NestedMeta::Meta(Meta::NameValue(MetaNameValue {
+ path,
+ lit: Lit::Str(bound_str_lit),
+ ..
+ })) if path.is_ident("bound") => {
+ bounds
+ .get_or_insert_with(Vec::new)
+ .push(bound_str_lit.parse_with(Punctuated::parse_terminated)?);
+ }
+ _ => {
+ return Err(Error::new_spanned(
+ attr,
+ format!(
+ "invalid `{}` attribute. expected `bound = \"..\"`",
+ ARBITRARY_ATTRIBUTE_NAME,
+ ),
+ ))
+ }
+ }
+ }
+ }
+
+ Ok(Self { bounds })
+ }
+}
diff --git a/src/field_attributes.rs b/src/field_attributes.rs
index ccaba74..2ca0f1c 100644
--- a/src/field_attributes.rs
+++ b/src/field_attributes.rs
@@ -1,10 +1,8 @@
+use crate::ARBITRARY_ATTRIBUTE_NAME;
use proc_macro2::{Group, Span, TokenStream, TokenTree};
use quote::quote;
use syn::{spanned::Spanned, *};
-/// Used to filter out necessary field attribute and within error messages.
-static ARBITRARY_ATTRIBUTE_NAME: &str = "arbitrary";
-
/// Determines how a value for a field should be constructed.
#[cfg_attr(test, derive(Debug))]
pub enum FieldConstructor {
diff --git a/src/lib.rs b/src/lib.rs
index 4ed3817..5e05522 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -4,9 +4,12 @@ use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::*;
+mod container_attributes;
mod field_attributes;
+use container_attributes::ContainerAttributes;
use field_attributes::{determine_field_constructor, FieldConstructor};
+static ARBITRARY_ATTRIBUTE_NAME: &str = "arbitrary";
static ARBITRARY_LIFETIME_NAME: &str = "'arbitrary";
#[proc_macro_derive(Arbitrary, attributes(arbitrary))]
@@ -18,6 +21,8 @@ pub fn derive_arbitrary(tokens: proc_macro::TokenStream) -> proc_macro::TokenStr
}
fn expand_derive_arbitrary(input: syn::DeriveInput) -> Result<TokenStream> {
+ let container_attrs = ContainerAttributes::from_derive_input(&input)?;
+
let (lifetime_without_bounds, lifetime_with_bounds) =
build_arbitrary_lifetime(input.generics.clone());
@@ -30,8 +35,13 @@ fn expand_derive_arbitrary(input: syn::DeriveInput) -> Result<TokenStream> {
gen_arbitrary_method(&input, lifetime_without_bounds.clone(), &recursive_count)?;
let size_hint_method = gen_size_hint_method(&input)?;
let name = input.ident;
- // Add a bound `T: Arbitrary` to every type parameter T.
- let generics = add_trait_bounds(input.generics, lifetime_without_bounds.clone());
+
+ // Apply user-supplied bounds or automatic `T: ArbitraryBounds`.
+ let generics = apply_trait_bounds(
+ input.generics,
+ lifetime_without_bounds.clone(),
+ &container_attrs,
+ )?;
// Build ImplGeneric with a lifetime (https://github.com/dtolnay/syn/issues/90)
let mut generics_with_lifetime = generics.clone();
@@ -77,6 +87,51 @@ fn build_arbitrary_lifetime(generics: Generics) -> (LifetimeDef, LifetimeDef) {
(lifetime_without_bounds, lifetime_with_bounds)
}
+fn apply_trait_bounds(
+ mut generics: Generics,
+ lifetime: LifetimeDef,
+ container_attrs: &ContainerAttributes,
+) -> Result<Generics> {
+ // If user-supplied bounds exist, apply them to their matching type parameters.
+ if let Some(config_bounds) = &container_attrs.bounds {
+ let mut config_bounds_applied = 0;
+ for param in generics.params.iter_mut() {
+ if let GenericParam::Type(type_param) = param {
+ if let Some(replacement) = config_bounds
+ .iter()
+ .flatten()
+ .find(|p| p.ident == type_param.ident)
+ {
+ *type_param = replacement.clone();
+ config_bounds_applied += 1;
+ } else {
+ // If no user-supplied bounds exist for this type, delete the original bounds.
+ // This mimics serde.
+ type_param.bounds = Default::default();
+ type_param.default = None;
+ }
+ }
+ }
+ let config_bounds_supplied = config_bounds
+ .iter()
+ .map(|bounds| bounds.len())
+ .sum::<usize>();
+ if config_bounds_applied != config_bounds_supplied {
+ return Err(Error::new(
+ Span::call_site(),
+ format!(
+ "invalid `{}` attribute. too many bounds, only {} out of {} are applicable",
+ ARBITRARY_ATTRIBUTE_NAME, config_bounds_applied, config_bounds_supplied,
+ ),
+ ));
+ }
+ Ok(generics)
+ } else {
+ // Otherwise, inject a `T: Arbitrary` bound for every parameter.
+ Ok(add_trait_bounds(generics, lifetime))
+ }
+}
+
// Add a bound `T: Arbitrary` to every type parameter T.
fn add_trait_bounds(mut generics: Generics, lifetime: LifetimeDef) -> Generics {
for param in generics.params.iter_mut() {