aboutsummaryrefslogtreecommitdiff
path: root/src/container_attributes.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/container_attributes.rs')
-rw-r--r--src/container_attributes.rs72
1 files changed, 72 insertions, 0 deletions
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 })
+ }
+}