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

Make Headers::remove return the header #898

Merged
merged 1 commit into from
Aug 23, 2016

Conversation

untitaker
Copy link
Contributor

Fix #891

@@ -82,6 +82,14 @@ impl Item {
}
self.typed.get_mut(tid).map(|typed| unsafe { typed.downcast_mut_unchecked() })
}

pub fn into_typed<H: Header>(self) -> Option<H> {
Copy link
Contributor Author

@untitaker untitaker Aug 22, 2016

Choose a reason for hiding this comment

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

Because a H may be unsized, I probably can only return Option<Box<Header + Send + Sync>> here. However, then I'm unsure how I'd be casting the box to a concrete type.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To be clear, I get a type conflict exactly at this spot: Expected H, got Box<Header + Send + Sync>. The first idea here is to add a new downcast_* method to impl Header + Send + Sync (again analogous to the get methods), but I don't know how to implement such a method.

Copy link
Member

Choose a reason for hiding this comment

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

Ah yes, of course, because the typed is storing them as Box<Header>. I think there is a way to add a downcast taking self by value, such as something like fn downcast(self: Box<Self>), but I'll toy on playground to find the right thing and report back.

Copy link
Member

Choose a reason for hiding this comment

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

Adding this to the impl Header + Send + Sync should do it:

#[inline]
unsafe fn downcast_unchecked<T: 'static>(self: Box<Self>) -> T {
    *(mem::transmute::<*mut _, (*mut (), *mut ())>(Box::into_raw(self)).0 as *mut T)
}

Then you can call val.downcast_unchecked() after having gotten the type from the TypeId.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately this doesn't work, apparently I can't deref *mut T.

Copy link
Member

Choose a reason for hiding this comment

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

Oh right. We can convert the *mut T into a Box<T> for free, with Box::from_raw, and then we can deref move out of the box:

*Box::from_raw(mem::transmute::<*mut _, (*mut (), *mut ())>(Box::into_raw(self)).0 as *mut T)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Amazing.

@seanmonstar
Copy link
Member

Oh woops, I didn't realize that the internal Item would need a new method, making this less easy than I suspected. Still, we should be able to figure it out.

@@ -320,10 +320,11 @@ impl Headers {
}

/// Removes a header from the map, if one existed.
/// Returns true if a header has been removed.
pub fn remove<H: Header>(&mut self) -> bool {
/// Returns the header, if one has been removed.
Copy link
Contributor Author

@untitaker untitaker Aug 22, 2016

Choose a reason for hiding this comment

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

This is actually incorrect. None may also be returned if the removed header was not parseable.

I wonder if we should return Option<(Raw, Option<H>)> or something like that instead, to enable as many usecases as possible.

Copy link
Member

Choose a reason for hiding this comment

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

Hm, I don't love that the return value could be more complicated, but how about this crazy idea: Option<Result<H, Raw>>...

I'd personally just drop it, but is there a convincing case where the raw is still needed to justify complicating the return type?

Copy link
Contributor Author

@untitaker untitaker Aug 22, 2016

Choose a reason for hiding this comment

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

I can't think of a reason why Raw is needed, but with the current return type there is no upgrade path for people who were checking the boolean value, as .is_some() is false even if the header was removed, but could not be parsed.

Copy link
Contributor Author

@untitaker untitaker Aug 22, 2016

Choose a reason for hiding this comment

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

Therefore Option<Option<H>> or Option<Result<H, ()>> would be appropriate if we don't want to bother with Raw.

Copy link
Member

Choose a reason for hiding this comment

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

Both feel yucky. I'd still prefer to just have Option<H>. The upgrade path could be to check headers.has() before calling remove().

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fair enough, I will update the docstring then.

@untitaker untitaker force-pushed the remove-returns-header branch 2 times, most recently from 2e29a3d to bc97d7b Compare August 23, 2016 19:14
@untitaker
Copy link
Contributor Author

@seanmonstar This should be ready to merge.

@seanmonstar
Copy link
Member

Looks right to me. Seems travis-ci's OSX containers are lagging, all the linux tests pass, so I'll merge anyways.

@seanmonstar seanmonstar merged commit 9375add into hyperium:master Aug 23, 2016
@untitaker
Copy link
Contributor Author

Thanks!

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