Skip to content

Add AttributeSet type#2419

Merged
casey merged 17 commits intocasey:masterfrom
neunenak:attributeset
Dec 10, 2024
Merged

Add AttributeSet type#2419
casey merged 17 commits intocasey:masterfrom
neunenak:attributeset

Conversation

@neunenak
Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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!

Comment thread src/analyzer.rs
let mut doc_attr: Option<&str> = None;
let mut groups = Vec::new();
for attribute in attributes {
attributes.ensure_valid_attributes(
Copy link
Copy Markdown
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
Copy Markdown
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.

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

impl<'src> Serialize for AttributeSet<'src> {
Copy link
Copy Markdown
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.

Comment thread src/attribute.rs Outdated
}
}

pub(crate) fn count(&self) -> usize {
Copy link
Copy Markdown
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.

Comment thread src/attribute.rs Outdated

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

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

pub(crate) fn private(&self) -> bool {
Copy link
Copy Markdown
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.

Comment thread src/parser.rs Outdated
Ok(None)
} else {
Ok(Some((token.unwrap(), attributes.into_keys().collect())))
let attribute_set = AttributeSet::from_iter(attributes.into_keys());
Copy link
Copy Markdown
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
Copy Markdown
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.

Comment thread src/recipe.rs Outdated
None
}
});
let extension = self
Copy link
Copy Markdown
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.

Comment thread 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
Copy Markdown
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.

Comment thread src/recipe.rs Outdated
}

for attribute in &self.attributes {
for attribute in self.attributes.iter() {
Copy link
Copy Markdown
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
@neunenak
Copy link
Copy Markdown
Contributor Author

neunenak commented Dec 2, 2024

@casey were there any more tweaks you wanted to make to this PR? It looks like some subsequent code merges have caused conflict with this PR, I'll try to fix them unless you had something specific you were trying to do with your commits.

Copy link
Copy Markdown
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.

Fixed the merge conflicts. I think this is fine. I have slight misgivings about needing to keep the sets of valid attributes in the ensure_valid_attributes call and match statement in sync, but I can't actually think of a way to improve it.

@casey casey enabled auto-merge (squash) December 10, 2024 23:31
@casey casey merged commit 462d381 into casey:master Dec 10, 2024
@neunenak neunenak deleted the attributeset branch December 12, 2024 21:35
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