-
Notifications
You must be signed in to change notification settings - Fork 165
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
FollowRedirect
: Move Policy::clone_body
to a separate trait
#125
Comments
I think this is a great idea! Especially
would be a very nice improvement! |
I did a quick experiment on implementing a part of the proposed API and I realized some oversights in the proposal.
This turned out to be non-trivial because Also, if we are going to adopt this API prior to the stabilization of impl<ReqBody, ResBody, S, P> Service<Request<ReqBody>> for FollowRedirect<S, P>
where
ReqBody: Body + Default + TryClone,
// ... But this would not work when // Naming is difficult...
pub enum WithClone {}
pub enum WithTryClone {}
pub enum NoClone {}
pub(crate) trait CloneStrategy<B> {
fn try_clone(body: &B) -> Option<B>;
}
impl<B: Clone> CloneStrategy<B> for WithClone {
fn try_clone(body: &B) -> Option<B> {
Some(body.clone())
}
}
impl<B: TryClone> CloneStrategy<B> for WithTryClone {
fn try_clone(body: &B) -> Option<B> {
body.try_clone()
}
}
impl<B> CloneStrategy<B> for NoClone {
fn try_clone(body: &B) -> Option<B> {
None
}
} Then add a new type parameter to The above idea solves the problem of trait bounds, but it comes with complexity cost with additional type parameter and constructors. It may simplify the use case with |
@Nehliin @MarcusGrass and I (all work at embark) and have talked about this a bit. We think given the number of unanswered questions here not gonna include this in tower-http 0.2. It feels having some answer to cloning requests would be useful for this as well, and also useful in general. So at some point we should research that. |
Feature Request
Motivation
FollowRedirect
tries to clone the request bodies usingPolicy::clone_body
function. But I believe that there is usually no more than one way to clone a body for each body type, so ideallyclone_body
should be be implemented once for a body type, rather than adding.and::<_, _, ()>(clone_body_fn(...))
to every instance ofimpl Policy
. Additionally, removingclone_body
fromPolicy<B, E>
lets us remove theB
parameter, which in turn removes theB
parameter ofPolicyExt
methods (which might also make it possible to bring the extension trait methods back toPolicy
trait (#79 (comment)), though I haven't experimented with it yet).Also, currently, you have to manually implement
Policy::<B, _>::clone_body
even ifB
implementsClone
. It would be great ifFollowRedirect
automatically clones the body whenB: Clone
.Proposal
Introduce
TryClone
(or whatever) trait that tries to cloneself
(request body):And make
FollowRedirect
use this trait instead ofPolicy::clone_body
function and remove that function.When
#![feature(stabilization)
(rust-lang/rust#31844) lands, we can implement the trait for anyB
whereB: 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, anhttp_body::Full
. Buttower_http
can implementTryClone
forhttp_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 implementclone_body
. For example,hyper::Body
internally hasOnce
variant which could in theory be cloned whereashyper::Body
itself is notClone
, 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
addsGenericBody
andEitherBody
types (hyperium/hyper#2345 (comment)) and makes their variants public, they would be affected by this drawback. But if they live undertower_http
instead (EitherBody
surely belongs there at least), we can simply implementTryClone
for them intower_http
.Also, this suggestion relies on
specialization
feature (instead ofmin_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 makingTryClone
trait private and usingTryClone::try_clone
as a fallback forPolicy::clone_body
.The text was updated successfully, but these errors were encountered: