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 support for std on containers and variants (fixes #5) #6

Merged
merged 1 commit into from
May 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 55 additions & 11 deletions crates/borrowme-macros/src/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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::<Token![=]>()?;
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."),
))
})
Expand Down Expand Up @@ -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<Variant, ()> {
pub(crate) fn variant(
cx: &Ctxt,
attrs: &[syn::Attribute],
container: &Container,
) -> Result<Variant, ()> {
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."),
))
})
Expand All @@ -134,6 +165,10 @@ pub(crate) fn variant(cx: &Ctxt, attrs: &[syn::Attribute]) -> Result<Variant, ()
}
}

if variant.kind.is_none() {
variant.kind = container.kind;
}

Ok(variant)
}

Expand Down Expand Up @@ -219,7 +254,12 @@ impl Field {
/// We provide `field_spans` so that the processed `FieldType::Type` can be
/// respanned to emit better diagnostics in case if fails something like a type
/// check.
pub(crate) fn field(cx: &Ctxt, spans: (Span, Span), attrs: &[syn::Attribute]) -> Result<Field, ()> {
pub(crate) fn field(
cx: &Ctxt,
spans: (Span, Span),
attrs: &[syn::Attribute],
default_kind: Option<(Span, FieldTypeKind)>,
) -> Result<Field, ()> {
let mut attr = Field {
is_mut: None,
ty: FieldType::default(),
Expand Down Expand Up @@ -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)
}

Expand Down
7 changes: 5 additions & 2 deletions crates/borrowme-macros/src/implement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand All @@ -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,
Expand Down Expand Up @@ -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<syn::FieldValue>,
Expand All @@ -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);

Expand Down
2 changes: 2 additions & 0 deletions crates/borrowme-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
//! [<img alt="crates.io" src="https://img.shields.io/crates/v/borrowme-macros.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/borrowme-macros)
//! [<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-borrowme--macros-66c2a5?style=for-the-badge&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" height="20">](https://docs.rs/borrowme-macros)

#![allow(clippy::too_many_arguments)]

mod attr;
mod ctxt;
mod implement;
Expand Down
81 changes: 73 additions & 8 deletions crates/borrowme/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = <ident>)]`][name] which is used to change the name of
/// the generated *owned* variant.
/// * [`#[borrowed_attr(<meta>)]`][b-c] and [`#[owned_attr(<meta>)]`][o-c] which
Expand Down Expand Up @@ -250,6 +253,37 @@
///
/// <br>
///
/// #### `#[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,
/// }
/// }
/// ```
///
/// <br>
///
/// #### `#[borrowme(name = <ident>)]` container attribute
///
/// This allows you to pick the name to use for the generated type. By default
Expand Down Expand Up @@ -328,6 +362,9 @@
///
/// * [`#[borrowed_attr(<meta>)]`][b-v] and [`#[owned_attr(<meta>)]`][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.
///
Expand Down Expand Up @@ -375,6 +412,32 @@
///
/// <br>
///
/// #### `#[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,
/// }
/// }
/// ```
///
/// <br>
///
///
/// <br>
///
/// ## Field attributes
///
/// This section documents supported field attributes:
Expand Down Expand Up @@ -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;

Expand Down
32 changes: 32 additions & 0 deletions crates/borrowme/tests/std_containers.rs
Original file line number Diff line number Diff line change
@@ -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,
},
}