Skip to content

Avoid unnecessary .expect()s for empty HeaderMap #768

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

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

Conversation

akonradi-signal
Copy link
Contributor

@akonradi-signal akonradi-signal commented May 21, 2025

This change removes the Result::expect()/unwrap() calls in the constructors for an empty HeaderMap. These calls were provably not going to fail at runtime but rustc's inliner wasn't smart enough to figure that out: strings analysis of compiled binaries showed that the error message to the expect() still showed up in generated code.

There are no behavioral differences as a result of this change.

Comment on lines 450 to 464
Self::new_empty()
}
}

impl<T> HeaderMap<T> {
fn new_empty() -> Self {
HeaderMap {
mask: 0,
indices: Box::new([]), // as a ZST, this doesn't actually allocate anything
entries: Vec::new(),
extra_values: Vec::new(),
danger: Danger::Green,
}
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Self::new_empty()
}
}
impl<T> HeaderMap<T> {
fn new_empty() -> Self {
HeaderMap {
mask: 0,
indices: Box::new([]), // as a ZST, this doesn't actually allocate anything
entries: Vec::new(),
extra_values: Vec::new(),
danger: Danger::Green,
}
}
HeaderMap {
mask: 0,
indices: Box::new([]), // as a ZST, this doesn't actually allocate anything
entries: Vec::new(),
extra_values: Vec::new(),
danger: Danger::Green,
}
}
}
impl<T> HeaderMap<T> {

I think it's simpler to make the new constructor initialize the empty map instead of adding a new method for it. Vec::new is implemented just like that, for example.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That was my first inclination but it would mean we can't use Self::new() in the Default impl because new() is only defined for HeaderMap<HeaderValue>, not HeaderMap<T>. If we want to try to eliminate the extra method I'd suggest instead making new() and try_with_capacity(0) call Default::default() and putting the actual definition in there. Alternatively we can move the definition of new() to the more general impl block below but that might break calling code that is relying on new() to constrain the generic type.

Copy link
Contributor Author

@akonradi-signal akonradi-signal May 22, 2025

Choose a reason for hiding this comment

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

I went ahead and did this in the latest commit. After looking at https://doc.rust-lang.org/cargo/reference/semver.html#fn-generalize-compatible I wouldn't be opposed to just making new() more generic since that's considered a non-breaking change even if breaks type inference in consumers. I'm happy to do that here if that's what maintainers prefer.

Edit: here's what that would look like: akonradi-signal@7f118aa. The tests had to be updated to handle the type inference breakage.

@akonradi-signal
Copy link
Contributor Author

Sent #769 to fix the nightly toolchain CI errors. They're unrelated to this PR.

This change removes the Result::expect() calls in the constructors for
an empty HeaderMap. These calls were provably not going to fail at
runtime but rustc's inliner wasn't smart enough to figure that out:
strings analysis of compiled binaries showed that the error message to
the expect() still showed up in generated code.

There are no behavioral differences as a result of this change.
@akonradi-signal akonradi-signal force-pushed the empty-header-map-no-expect branch from ce1bfa3 to 43228c1 Compare May 21, 2025 19:53
This gives us one fewer named method since we can use default() in place
of new_empty(). It preserves the property that `HeaderMap::new()`
constrains the generic type to `T=HeaderValue`.
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