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

API: substitute Result<Future..> with Future.. for more idiomatic future chaining #49

Conversation

steveej
Copy link
Contributor

@steveej steveej commented Oct 17, 2018

This change is motivated by an out-of-band discussion with @lucab and a comment on a related PR openshift/cincinnati#4 (comment) by @crawford, suggesting to use future chaining.

Before this PR all methods return a Result<Future..> chaining them requires to unwrap() or slightly milder unwrap_or_else() for every additional chain element, which adds significant boilerplate for the consumer. This PR aims to aid with this by removing the outer Result<Future..> and return Future.. for all async public methods.

I'd like to discuss this API breaking change with the intention to move forward with this or a similar approach for the whole crate. I've done a rewrite of the login example demonstrates the usage of the changed API.


  • Rewrite all of the examples to use the new API
  • Rewrite examples to use chaining
    • examples/checkregistry.rs
    • examples/image.rs
    • examples/login.rs
    • examples/tags.rs
    • examples/trace.rs
  • Rewrite all of the? API

@steveej steveej force-pushed the return-future-without-result-and-work-examples branch from 2f36b4c to 2a18364 Compare October 17, 2018 14:48
@steveej steveej changed the title [WIP] return-future-uncapsuled-and-rewrite-examples [WIP/RFC] API: substitute Result<Future*> with Future* for more idiomatic future chaining Oct 17, 2018
src/v2/auth.rs Outdated
let subclient = self.hclient.clone();
let creds = self.credentials.clone();
let scope = scopes
.iter()
.fold("".to_string(), |acc, &s| acc + "&scope=" + s);
let auth = self
.get_token_provider()?
.get_token_provider()
.unwrap()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

FIXME

src/v2/mod.rs Outdated
let url = try!(hyper::Uri::from_str(
(self.base_url.clone() + "/v2/").as_str()
));
let url = hyper::Uri::from_str((self.base_url.clone() + "/v2/").as_str()).unwrap();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

FIXME

@steveej steveej changed the title [WIP/RFC] API: substitute Result<Future*> with Future* for more idiomatic future chaining [WIP/RFC] API: substitute Result<Future..> with Future.. for more idiomatic future chaining Oct 17, 2018
@lucab
Copy link
Member

lucab commented Oct 17, 2018

I would say that yes, we should try to drop the outer Result<> and convert the error case into an inner future result. The current API is my first attempt at a futures-based library, as you can see...

@steveej steveej force-pushed the return-future-without-result-and-work-examples branch 4 times, most recently from 4f5a625 to d1bdb2a Compare October 23, 2018 18:14
@steveej
Copy link
Contributor Author

steveej commented Oct 23, 2018

I've changed all methods referenced by the examples. A first review pass would make sense now ;-)

@steveej steveej requested a review from lucab October 23, 2018 19:45
@steveej steveej force-pushed the return-future-without-result-and-work-examples branch 2 times, most recently from 64255ef to 8b7b13f Compare October 24, 2018 09:20
.and_then(|dclient| {
dclient.is_v2_supported().and_then(|v2_supported| {
if !v2_supported {
return Err("API v2 not supported".into());
Copy link
Member

Choose a reason for hiding this comment

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

You can drop the explicit return here (or flatten the else branch).

}).and_then(|dclient| {
dclient.is_auth(None).and_then(|is_auth| {
if is_auth {
return Err("no login performed, but already authenticated".into());
Copy link
Member

Choose a reason for hiding this comment

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

Same as above.

}
dkregistry::mediatypes::MediaTypes::ManifestV2S2 => {
let m: dkregistry::v2::manifest::ManifestSchema2 =
serde_json::from_slice(manifest_body.as_slice()).unwrap();
Copy link
Member

Choose a reason for hiding this comment

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

There are two leftover unwraps here and in the match-arm above.

examples/image.rs Show resolved Hide resolved
extern crate tokio_core;

use std::{boxed, error};
use tokio_core::reactor::Core;

use futures::future::Future;
Copy link
Member

Choose a reason for hiding this comment

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

Just use the prelude here too.

examples/tags.rs Outdated
})
}).and_then(|dclient| {
dclient
.login(&[&format!("repository:{}:pull", image)])
Copy link
Member

Choose a reason for hiding this comment

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

I would extract the scope-formatting outside (before) the start of the chain, so that it's harder for people to miss (here and everywhere else too).

examples/tags.rs Outdated
} else {
println!("logged in!");
Ok(dclient
.clone()
Copy link
Member

Choose a reason for hiding this comment

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

Is this clone really needed?

Copy link
Contributor Author

@steveej steveej Oct 24, 2018

Choose a reason for hiding this comment

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

Yes, because:

error[E0596]: cannot borrow immutable captured outer variable in an `FnOnce` closure `dclient` as mutable
  --> examples/tags.rs:77:36
   |
77 |                                 Ok(dclient
   |                                    ^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0596`.
error: Could not compile `dkregistry`.

src/v2/blobs.rs Outdated
let cl = self.clone();
let url = {
let ep = format!("{}/v2/{}/blobs/{}", self.base_url.clone(), name, digest);
hyper::Uri::from_str(ep.as_str())?
hyper::Uri::from_str(ep.as_str()).unwrap()
Copy link
Member

Choose a reason for hiding this comment

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

Leftover unwrap (there are a few more below without a fixme note).

@steveej steveej force-pushed the return-future-without-result-and-work-examples branch 6 times, most recently from d4199d0 to 10aafe8 Compare October 24, 2018 21:08
Before this commit all methods return a `Result<Future..>` chaining them
requires to `unwrap()` or slightly milder `unwrap_or_else()` for *every*
additional chain element, which adds significant boilerplate for the
consumer. This commit aims to aid with this by removing the outer
`Result<Future..>` and return `Future..` for all async public methods.
@steveej steveej force-pushed the return-future-without-result-and-work-examples branch from 10aafe8 to 363baf3 Compare October 24, 2018 21:31
@steveej steveej changed the title [WIP/RFC] API: substitute Result<Future..> with Future.. for more idiomatic future chaining API: substitute Result<Future..> with Future.. for more idiomatic future chaining Oct 24, 2018
@steveej steveej force-pushed the return-future-without-result-and-work-examples branch from 363baf3 to 8ac4299 Compare October 24, 2018 21:35
@steveej steveej requested a review from lucab October 24, 2018 21:36
"{}/v2/{}/manifests/{}",
self.base_url.clone(),
name,
reference
)));
)).unwrap();
Copy link
Member

Choose a reason for hiding this comment

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

Leftover unwrap.

.append(header::ACCEPT, header::HeaderValue::from_str(&mtype)?);
r.headers_mut().append(
header::ACCEPT,
header::HeaderValue::from_str(&mtype).unwrap(),
Copy link
Member

Choose a reason for hiding this comment

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

Leftover unwrap.

let url = {
let ep = format!(
"{}/v2/{}/manifests/{}",
self.base_url.clone(),
name,
reference
);
try!(hyper::Uri::from_str(ep.as_str()))
hyper::Uri::from_str(ep.as_str()).unwrap()
Copy link
Member

Choose a reason for hiding this comment

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

Leftover unwrap.

};
let accept_types = match mediatypes {
None => vec![mediatypes::MediaTypes::ManifestV2S2.to_mime()],
Some(ref v) => try!(to_mimes(v)),
Some(ref v) => to_mimes(v).unwrap(),
Copy link
Member

Choose a reason for hiding this comment

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

Leftover unwrap.

src/v2/tags.rs Outdated
let url = {
let mut s = format!("{}/v2/{}/tags/list", self.base_url, name);
if let Some(n) = paginate {
s = s + &format!("?n={}", n);
};
try!(hyper::Uri::from_str(s.as_str()))
hyper::Uri::from_str(s.as_str()).unwrap()
Copy link
Member

Choose a reason for hiding this comment

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

Leftover unwrap.

@lucab
Copy link
Member

lucab commented Oct 24, 2018

@steveej this looks pretty good to me. There are only five leftover unwraps and then I think it's done.

@steveej
Copy link
Contributor Author

steveej commented Oct 25, 2018

Yay, more unwraps to clear up 🎂 Thanks for catching these

@steveej steveej force-pushed the return-future-without-result-and-work-examples branch from 8498ddc to 8452a89 Compare October 25, 2018 10:05
@steveej steveej force-pushed the return-future-without-result-and-work-examples branch 3 times, most recently from d2bf4ac to a1fc31b Compare October 25, 2018 13:17
@steveej steveej requested a review from lucab October 25, 2018 15:05
Copy link
Member

@lucab lucab left a comment

Choose a reason for hiding this comment

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

LGTM

`git grep -e 'unwrap()' --and --not -e '^//' -n src/` doesn't indicate
any occurences left.
@steveej steveej force-pushed the return-future-without-result-and-work-examples branch from a1fc31b to 8f0dabe Compare October 25, 2018 17:01
@steveej steveej merged commit 23adf75 into camallo:master Oct 27, 2018
@steveej steveej deleted the return-future-without-result-and-work-examples branch October 27, 2018 12:02
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