`FollowRedirect`: Move `Policy::clone_body` to a separate trait
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 25/100
- Issue type
- Feature
- Clarity
- Needs clarification
- Activity status
- Stale
- Tech stack
- rust
- Domain
- backend-api-design, networking
Research direction
Start by tracing FollowRedirect, Policy::clone_body, and the PolicyExt methods described in the issue. Review the proposed TryClone trait and the specialization and API alternatives before deciding on the design. Done means FollowRedirect uses the selected cloning approach and the existing Policy and PolicyExt API implications are addressed.
Written by the indexing model from the issue text.
Description
Feature Request
Motivation
FollowRedirect tries to clone the request bodies using Policy::clone_body function. But I believe that there is usually no more than one way to clone a body for each body type, so ideally clone_body should be be implemented once for a body type, rather than adding .and::<_, _, ()>(clone_body_fn(...)) to every instance of impl Policy. Additionally, removing clone_body from Policy<B, E> lets us remove the B parameter, which in turn removes the B parameter of PolicyExt methods (which might also make it possible to bring the extension trait methods back to Policy trait (https://github.com/tower-rs/tower-http/pull/79#discussion_r598262626), though I haven't experimented with it yet).
Also, currently, you have to manually implement Policy::<B, _>::clone_body even if B implements Clone. It would be great if FollowRedirect automatically clones the body when B: Clone.
Proposal
Introduce TryClone (or whatever) trait that tries to clone self (request body):
pub trait TryClone: Sized {
fn try_clone(&self) -> Option<Self>;
}
// User code
pub enum MyBody {
Stream(/* ... */),
Full(/* ... */),
}
impl TryClone for MyBody {
fn try_clone(&self) -> Option<Self> {
match self {
MyBody::Stream(/* ... */) => None,
MyBody::Full(/* ... */) => Some(MyBody::Full(/* ... */))
}
}
}
And make FollowRedirect use this trait instead of Policy::clone_body function and remove that function.
When #![feature(stabilization) (https://github.com/rust-lang/rust/issues/31844) lands, we can implement the trait for any B where B: Clone:
pub trait TryClone: Sized {
fn try_clone(&self) -> Option<Self>;
}
impl<T> TryClone for T {
default fn try_clone(&self) -> Option<Self> {
None
}
}
impl<T: Clone> TryClone for T {
fn try_clone(&self) -> Option<Self> {
Some(self.clone())
}
}
Drawbacks
In user code, TryClone cannot be implemented for types from third party crates and, without specialization, you would end up being unable to clone, for example, an http_body::Full. But tower_http can implement TryClone for http_body's body types in the meantime.
Even with specialization, the trait cannot be implemented for non-Clone third-party body types. However, I expect its impact to be small in practice because few (if any) body types out there expose interfaces that let third party code implement clone_body. For example, hyper::Body internally has Once variant which could in theory be cloned whereas hyper::Body itself is not Clone, but in fact there is no way for third party code to reference the variant and clone it.
Though, it should be noted that if hyper adds GenericBody and EitherBody types (https://github.com/hyperium/hyper/issues/2345#issuecomment-734982106) and makes their variants public, they would be affected by this drawback. But if they live under tower_http instead (EitherBody surely belongs there at least), we can simply implement TryClone for them in tower_http.
Also, this suggestion relies on specialization feature (instead of min_specialization as it stands), whose path towards stabilization is still very unclear.
Alternatives
Keep the current API as-is. We may well want to wait until specialization feature stabilizes. Also, we can apply the specialization trick in the proposal even while keeping the API in its current form, by making TryClone trait private and using TryClone::try_clone as a fallback for Policy::clone_body.
- Dominant language
- Rust
- Stars
- 913
- Forks
- 231
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 8
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from tower-rs/tower-http
-
Difficulty 4/5 3-5 days Newbie friendliness 35/100
tower-rs/tower-http#737 · 2 comments ·
-
Difficulty 3/5 1-2 days Newbie friendliness 65/100
tower-rs/tower-http#732 ·
-
Difficulty 3/5 1-2 days Newbie friendliness 68/100
tower-rs/tower-http#731 ·
-
Difficulty 5/5 Over a week Newbie friendliness 30/100
tower-rs/tower-http#701 · 2 reactions ·
-
Difficulty 4/5 3-5 days Newbie friendliness 45/100
tower-rs/tower-http#657 · 12 comments · 1 reaction ·
All issues in tower-rs/tower-http
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
kwakseongjae/auto-hwp#319 ·
-
area:cli bug filter-quality good first issue priority:medium
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
-
Difficulty 1/5 Under an hour Newbie friendliness 72/100
bevyengine/bevy#25861 ·
-
comp-datalake
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
ClickHouse/ClickHouse#121222 ·
-
enhancement remote
Difficulty 2/5 1-3 hours Newbie friendliness 68/100