diff --git a/crates/borrowme-macros/src/attr.rs b/crates/borrowme-macros/src/attr.rs index 201625a..ca8191a 100644 --- a/crates/borrowme-macros/src/attr.rs +++ b/crates/borrowme-macros/src/attr.rs @@ -32,6 +32,8 @@ pub(crate) struct Container { pub(crate) owned_ident: Option<(Span, syn::Ident)>, /// Attributes to apply. pub(crate) attributes: Attributes, + /// Default field type kind. + pub(crate) kind: Option<(Span, FieldTypeKind)>, } impl Container { @@ -53,25 +55,34 @@ pub(crate) fn container( let mut attr = Container { owned_ident: None, attributes: Attributes::default(), + kind: None, }; + macro_rules! set_attr { + ($field:ident $(. $field2:ident)*, $meta:expr, $value:expr, $message:expr $(,)?) => { + set_attr(cx, &mut attr.$field$(.$field2)*, $meta, $value, $message) + } + } + for a in attrs.iter().chain(rest) { let result = if a.path().is_ident(BORROWME) { a.parse_nested_meta(|meta| { + let span = meta.path.span(); + if meta.path.is_ident("name") { meta.input.parse::()?; - set_attr( - cx, - &mut attr.owned_ident, - meta.path.span(), - meta.input.parse()?, - "Duplicate name.", - ); + set_attr!(owned_ident, span, meta.input.parse()?, "Duplicate name.",); + return Ok(()); + } + + if meta.path.is_ident("std") { + let kind = FieldTypeKind::Std; + set_attr!(kind, span, kind, "Duplicate container field kind."); return Ok(()); } Err(syn::Error::new( - meta.path.span(), + span, format_args!("#[{BORROWME}]: Unsupported attribute."), )) }) @@ -99,19 +110,39 @@ pub(crate) fn container( pub(crate) struct Variant { pub(crate) attributes: Attributes, + pub(crate) kind: Option<(Span, FieldTypeKind)>, } /// Parse variant attributes. -pub(crate) fn variant(cx: &Ctxt, attrs: &[syn::Attribute]) -> Result { +pub(crate) fn variant( + cx: &Ctxt, + attrs: &[syn::Attribute], + container: &Container, +) -> Result { let mut variant = Variant { attributes: Attributes::default(), + kind: None, }; + macro_rules! set_attr { + ($field:ident $(. $field2:ident)*, $meta:expr, $value:expr, $message:expr $(,)?) => { + set_attr(cx, &mut variant.$field$(.$field2)*, $meta, $value, $message) + } + } + for a in attrs { let result = if a.path().is_ident(BORROWME) { a.parse_nested_meta(|meta| { + let span = meta.path.span(); + + if meta.path.is_ident("std") { + let kind = FieldTypeKind::Std; + set_attr!(kind, span, kind, "Duplicate variant field kind."); + return Ok(()); + } + Err(syn::Error::new( - meta.path.span(), + span, format_args!("#[{BORROWME}]: Unsupported attribute."), )) }) @@ -134,6 +165,10 @@ pub(crate) fn variant(cx: &Ctxt, attrs: &[syn::Attribute]) -> Result Result { +pub(crate) fn field( + cx: &Ctxt, + spans: (Span, Span), + attrs: &[syn::Attribute], + default_kind: Option<(Span, FieldTypeKind)>, +) -> Result { let mut attr = Field { is_mut: None, ty: FieldType::default(), @@ -376,6 +416,10 @@ pub(crate) fn field(cx: &Ctxt, spans: (Span, Span), attrs: &[syn::Attribute]) -> } } + if attr.ty.kind.is_none() { + attr.ty.kind = default_kind; + } + Ok(attr) } diff --git a/crates/borrowme-macros/src/implement.rs b/crates/borrowme-macros/src/implement.rs index a876aff..0643cfe 100644 --- a/crates/borrowme-macros/src/implement.rs +++ b/crates/borrowme-macros/src/implement.rs @@ -188,6 +188,7 @@ pub(crate) fn implement( process_fields( cx, Access::SelfAccess, + attr.kind, &mut o_st.fields, &mut b_st.fields, &mut to_owned_entries, @@ -250,7 +251,7 @@ pub(crate) fn implement( let borrow_ident = b_en.ident.clone(); for (o_variant, b_variant) in o_en.variants.iter_mut().zip(b_en.variants.iter_mut()) { - let attr = attr::variant(cx, &o_variant.attrs)?; + let attr = attr::variant(cx, &o_variant.attrs, &attr)?; attr::strip([&mut o_variant.attrs, &mut b_variant.attrs]); apply_attributes(&attr.attributes, &mut o_variant.attrs, &mut b_variant.attrs); @@ -261,6 +262,7 @@ pub(crate) fn implement( process_fields( cx, Access::BindingAccess, + attr.kind, &mut o_variant.fields, &mut b_variant.fields, &mut to_owned_entries, @@ -419,6 +421,7 @@ pub(crate) fn implement( fn process_fields( cx: &Ctxt, access: Access, + default_kind: Option<(Span, attr::FieldTypeKind)>, o_fields: &mut syn::Fields, b_fields: &mut syn::Fields, to_owned_entries: &mut Vec, @@ -428,7 +431,7 @@ fn process_fields( for (index, (o_field, b_field)) in o_fields.iter_mut().zip(b_fields.iter_mut()).enumerate() { let field_ty_spans = field_ty_spans(o_field); - let mut attr = attr::field(cx, field_ty_spans, &o_field.attrs)?; + let mut attr = attr::field(cx, field_ty_spans, &o_field.attrs, default_kind)?; attr::strip([&mut o_field.attrs, &mut b_field.attrs]); apply_attributes(&attr.attributes, &mut o_field.attrs, &mut b_field.attrs); diff --git a/crates/borrowme/src/lib.rs b/crates/borrowme/src/lib.rs index fcf52ed..ba11e5f 100644 --- a/crates/borrowme/src/lib.rs +++ b/crates/borrowme/src/lib.rs @@ -223,6 +223,9 @@ /// /// This section documents supported container attributes: /// +/// * [`#[borrowme(std)]`][container-std] which acts as if +/// [`#[borrowme(std)]`][std] is applied to every field and variant in the +/// container by default. /// * [`#[borrowme(name = )]`][name] which is used to change the name of /// the generated *owned* variant. /// * [`#[borrowed_attr()]`][b-c] and [`#[owned_attr()]`][o-c] which @@ -250,6 +253,37 @@ /// ///
/// +/// #### `#[borrowme(std)]` container attribute +/// +/// This container attribute acts as if [`#[borrowme(std)]`][std] is applied to +/// every field or variant in the container. +/// +/// Note that this defeats copy and reference heuristics. +/// +/// ``` +/// use borrowme::borrowme; +/// +/// #[borrowme] +/// #[borrowme(std)] +/// struct StdStruct<'a> { +/// a: &'a String, +/// #[borrowme(copy)] +/// b: u32, +/// } +/// +/// #[borrowme] +/// #[borrowme(std)] +/// enum StdEnum<'a> { +/// Variant { +/// a: &'a String, +/// #[borrowme(copy)] +/// b: u32, +/// } +/// } +/// ``` +/// +///
+/// /// #### `#[borrowme(name = )]` container attribute /// /// This allows you to pick the name to use for the generated type. By default @@ -328,6 +362,9 @@ /// /// * [`#[borrowed_attr()]`][b-v] and [`#[owned_attr()]`][o-v] which /// are used to add custom attributes. +/// * [`#[borrowme(std)]`][variant-std] which acts as if +/// [`#[borrowme(std)]`][std] is applied to every field in the variant by +/// default. /// /// Variant attributes are attributes which apply to `enum` variants. /// @@ -375,6 +412,32 @@ /// ///
/// +/// #### `#[borrowme(std)]` variant attribute +/// +/// This container attribute acts as if [`#[borrowme(std)]`][std] is applied to +/// every field inside of a variant. +/// +/// Note that this defeats copy and reference heuristics. +/// +/// ``` +/// use borrowme::borrowme; +/// +/// #[borrowme] +/// enum StdEnum<'a> { +/// #[borrowme(std)] +/// Variant { +/// a: &'a String, +/// #[borrowme(copy)] +/// b: u32, +/// } +/// } +/// ``` +/// +///
+/// +/// +///
+/// /// ## Field attributes /// /// This section documents supported field attributes: @@ -756,20 +819,22 @@ /// } /// ``` /// -/// [name]: #borrowmename--ident-container-attribute /// [b-c]: #borrowed_attrmeta-container-attribute -/// [o-c]: #owned_attrmeta-container-attribute +/// [b-f]: #borrowed_attrmeta-field-attribute /// [b-v]: #borrowed_attrmeta-variant-attribute -/// [o-v]: #owned_attrmeta-variant-attribute -/// [owned]: #ownedtype-or-borrowmeowned--type-field-attributes -/// [to_owned_with]: #borrowmeto_owned_with--path-field-attribute /// [borrow_with]: #borrowmeborrow_with--path-field-attribute -/// [with]: #borrowmewith--path-field-attribute +/// [container-std]: #borrowmestd-container-attribute /// [copy]: #copy-and-no_copy-field-attribute -/// [std]: #borrowmestd-field-attribute /// [mut]: #borrowmemut-field-attribute -/// [b-f]: #borrowed_attrmeta-field-attribute +/// [name]: #borrowmename--ident-container-attribute +/// [o-c]: #owned_attrmeta-container-attribute /// [o-f]: #owned_attrmeta-field-attribute +/// [o-v]: #owned_attrmeta-variant-attribute +/// [owned]: #ownedtype-or-borrowmeowned--type-field-attributes +/// [std]: #borrowmestd-field-attribute +/// [to_owned_with]: #borrowmeto_owned_with--path-field-attribute +/// [variant-std]: #borrowmestd-variant-attribute +/// [with]: #borrowmewith--path-field-attribute #[doc(inline)] pub use borrowme_macros::borrowme; diff --git a/crates/borrowme/tests/std_containers.rs b/crates/borrowme/tests/std_containers.rs new file mode 100644 index 0000000..c919aae --- /dev/null +++ b/crates/borrowme/tests/std_containers.rs @@ -0,0 +1,32 @@ +use borrowme::borrowme; + +#[borrowme] +#[borrowme(std)] +#[derive(Clone)] +struct StdStruct<'a> { + a: &'a String, + #[borrowme(copy)] + b: u32, +} + +#[borrowme] +#[borrowme(std)] +#[derive(Clone)] +enum StdOnEnum<'a> { + Variant { + a: &'a String, + #[borrowme(copy)] + b: u32, + }, +} + +#[borrowme] +#[derive(Clone)] +enum StdVariant<'a> { + #[borrowme(std)] + Variant { + a: &'a String, + #[borrowme(copy)] + b: u32, + }, +}