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 AttributeSet type #2419

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open

Add AttributeSet type #2419

wants to merge 14 commits into from

Conversation

neunenak
Copy link
Contributor

@neunenak neunenak commented Oct 8, 2024

Replace the several places that directly use a BTreeSet<Attribute> with a wrapper data structure AttributeSet, that provides some convenience methods for working with attributes.

@neunenak
Copy link
Contributor Author

neunenak commented Oct 8, 2024

I think having a data structure like this will make it easier to implement #1895 , and it's an independently-reviewable chunk of work so it doesn't have to be part of #2393 .

Copy link
Owner

@casey casey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, this is a definite improvement. See comments!

@@ -69,17 +69,17 @@ impl<'run, 'src> Analyzer<'run, 'src> {
} => {
let mut doc_attr: Option<&str> = None;
let mut groups = Vec::new();
for attribute in attributes {
attributes.ensure_valid_attributes(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should keep the error checking in the else below, otherwise the set of allowed attributes is in two places, here, where we call ensure_valid_attributes, and below, in the if / else statement.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we keep the error checking here, then we would have pretty similar error-generation code here and in the ensure_valid_attributes method. I added ensure_valid_attributes as a way of de-duplicating attribute error generation code. I modified the code below to add an unreachable and hopefully make it clearer what's going on.

src/attribute.rs Outdated
inner: BTreeSet<Attribute<'src>>,
}

impl<'src> Serialize for AttributeSet<'src> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we avoid needing to write a custom a serialize implementation if we make the struct:

pub(crate) struct AttributeSet<'src>(BTreeSet<Attribute<'src>>);

I think in that case serde will serialize the struct as just the inner contents.

src/attribute.rs Outdated
}
}

pub(crate) fn count(&self) -> usize {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should just call this len, since that's what native collections use.

src/attribute.rs Outdated

pub(crate) fn contains(&self, target: AttributeDiscriminant) -> bool {
self.inner.iter().any(|attr| {
let discriminant: AttributeDiscriminant = attr.into();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a fn discriminant(&self) -> AttributeDiscriminant { self.into() } function to Attribute, so we can avoid needing to use type inference to do the conversion.

src/attribute.rs Outdated
self.inner.iter()
}

pub(crate) fn private(&self) -> bool {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should avoid one-off helpers like this, unless they do something more complex, since doing attributes.contains(AttributeDiscriminant::Private) isn't so bad.

src/parser.rs Outdated
@@ -1128,7 +1115,8 @@ impl<'run, 'src> Parser<'run, 'src> {
if attributes.is_empty() {
Ok(None)
} else {
Ok(Some((token.unwrap(), attributes.into_keys().collect())))
let attribute_set = AttributeSet::from_iter(attributes.into_keys());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you do collect here instead of from_iter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quite sure what code change you want to see here.

src/recipe.rs Outdated
None
}
});
let extension = self
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the original version of this is actually better, since we don't duplicate which attribute we're looking for.

src/recipe.rs Outdated
if let Attribute::Doc(doc) = attribute {
return doc.as_ref().map(|s| s.cooked.as_ref());
}
if let Some(Attribute::Doc(doc)) = self.attributes.get(AttributeDiscriminant::Doc) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is kind of a weird one. This if let will only match if both self.attributes.get returns Some, and the returned attribute is an Attribute::Doc, if the code is correct, of course, both or neither will be the case.

I think a more scrupulous correct version would be:

if let Some(attribute) = self.attributes.get(AttributeDiscriminant::Doc) {
  if let Some(Attribute::Doc(doc)) else {
    unreachable!();
  }
}

Although that's a little crazy, so I think maybe the original on the left is better.

src/recipe.rs Outdated
@@ -479,7 +483,7 @@ impl<'src, D: Display> ColorDisplay for Recipe<'src, D> {
writeln!(f, "# {doc}")?;
}

for attribute in &self.attributes {
for attribute in self.attributes.iter() {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should implement IntoIterator for &AttributeSet so we can avoid needing to call .iter().

@neunenak neunenak requested a review from casey November 2, 2024 08:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants