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
Raw byte access for Headers is not ergonomic #50
Comments
The issue is that it is not possible to provide the granular guarantee to the type system/borrow checker that no two headers with the same name are accessed concurrently. The |
Additionally, while for most use-cases, the Typed API should be preferred, Servo has a legitimate reason for accessing all the Raw headers: providing the JS methods Those restraints mean that we cannot do what is currently done: we must keep the raw bytes around even if accessed as a Typed value. The steps I think we need are:
Alternatives: instead of a |
I was thinking about allowing access to raw headers through a type which just wraps a regular header and returns the input in parse_header - for instance However, I didn't consider that this still doesn't allow for dynamic raw header access through strings. On Wed, Sep 24, 2014 at 11:15 PM, Sean McArthur notifications@github.com
|
I think that we can provide both |
Any reason to receive a |
I just spent some time whiteboarding this issue, and I think that I've found a pretty good solution: struct Headers { .. }
impl Headers {
// Typed
fn get<'a, M: Marker>(&'a self) -> Option<HeaderView<'a, M>>;
fn set<M: Marker, H: Header<M>>(&mut self, H);
// Raw
fn get_raw<'a>(&'a self, &str) -> Option<RawView<'a>>;
fn set_raw(&self, &str, Vec<Vec<u8>>);
}
struct HeaderView<'a, M: Marker> {
item: &'a HeaderItem
}
struct HeaderItem(RWLock<Box<Header<Erased> + Send + Sync>>);
impl<M: Marker> HeaderView<M> {
fn as<'a, H: Header<M>>(&'a self) -> Option<ReadGuard<'a, H>>
fn as_mut<'a, H: Header<M>>(&'a self) -> Option<WriteGuard<'a, H>>
}
// A bit of hypothetical Associated Statics syntax. Takes the form header_name in real code today.
struct Erased; impl Marker for Erased { name = "" };
trait Marker { name: &'static str; }
trait Header<M: Marker> {} // current methods, minus name stuff
// RawView works a lot like HeaderView except it parses to
// ReadGuard<Vec<Vec<u8>]> and WriteGuard<Vec<Vec<u8>>> This allows multiple headers to be accessed at once with minimum likelihood of stepping on each-others toes. It has some of the same issues as just returning If you think this API might be valuable, I can take a shot at implementing it. |
Here's a gist with the meat of the above implementation, corrected for reality: https://gist.github.com/27fb134d2554572b21f8 (Untested, uncompiled code) |
I've been thinking about the above interface and I'm having second thoughts. The interface is unfortunately not as safe as just taking By introducing the marker and separating |
Sorry about the late response, work gets in the way some days. I'd like to take a second to map out exact objectives, so the end goal is clearer. I'll probably update the initial comment with the points. |
Here's a crazy idea. What if we didn't store the typed version after Instead, by not storing the typed value, we don't need a mutable borrow to Getting a different type for the same header would still have required a |
I think the performance implications of that are too bad. |
Yea, cloning would be faster than reparsing. Still, I can't imagine needing Anyway, I'm trying it in a branch and we can see benchmarks. |
I'm worried that it will be particularly nasty for certain complex headers, but stats are always better than speculation. |
This is mostly dealt with. Specific pain points can become new issues, if needed. |
We invalidate raw headers, will soon return *const, etc.
The story here is complex. You can treat the Raw representation as just another Typed header, except this one is
Raw(&[Vec<u8>])
or so, so the problem devolves to providing safe re-parsing of headers. This is possible through one of three methods:&mut self
in every getter method.RWLock
and returnRWLockReadGuard
orRWLockWriteGuard
, depending.RefCell
to vastly simplify the code, and returnRef
orRefMut
, depending.Rc
orArc
and otherwise make life simpler by introducing refcounting.The first approach is not ergonomic:
The second is liable to cause deadlocks:
The third is liable to cause runtime errors in the same way, and the fourth introduces a possibly ridiculous amount of overhead.
The text was updated successfully, but these errors were encountered: