Skip to content

Instantly share code, notes, and snippets.

@igalic
Created December 8, 2018 13:39
Show Gist options
  • Save igalic/6261f3f0124d2115cf88c31f7916a706 to your computer and use it in GitHub Desktop.
Save igalic/6261f3f0124d2115cf88c31f7916a706 to your computer and use it in GitHub Desktop.
match req {
Ok(mut res) => {
if let Ok(text) = &res.text() {
if let Ok(ap_sign) = serde_json::from_str::<ApSignature>(text) {
if let Ok(mut json) = serde_json::from_str::<CustomPerson>(text) {
json.custom_props = ap_sign; // without this workaround, publicKey is not correctly deserialized
Some(json)
} else {
None
}
} else {
None
}
} else {
None
}
}
Err(e) => {
println!("User fetch error: {:?}", e);
None
}
}
@AlexEne
Copy link

AlexEne commented Dec 8, 2018

Actually they are Results so you can use ?. Something like:

                let res = res?;
                let text = &res.text()?;
                let let ap_sign = serde_json::from_str::<ApSignature>(text)?;
                let mut json= serde_json::from_str::<CustomPerson>(text)?;
                json.custom_props = ap_sign; // without this workaround, publicKey is not correctly deserialized

@aledomu
Copy link

aledomu commented Dec 8, 2018

Although they are Result, if you really want to return an Option, just add .ok() before each ? (it works with Option too). Keeping the return types the same and the print macro (untested):

let mut res = req
    .or_else(|e| {
        println!("User fetch error: {:?}", e);
        Err(e) })
    .ok()?;
let text = &res.text().ok()?;
let mut json = serde_json::from_str::<CustomPerson>(text).ok()?
let ap_sign = serde_json::from_str::<ApSignature>(text).ok()?;
json.custom_props = ap_sign;
Some(json)

However I would try to return a Result, do the same as the first suggestion and manage the Err from the calling function.

@ooooak
Copy link

ooooak commented Dec 8, 2018

You can use ? in a match expiration too.

match req? {

}

@spamwax
Copy link

spamwax commented Dec 8, 2018

Using and_then:

let stuff = req
     .and_then(|res| {
          res.text().and_then(|text| {
              serde_json::from_str::<ApSignature>(text).and_then(|ap_sign| {
                  serde_json::from_str::<CustomPerson>(text).map(|mut json| {
                      json.custom_props = ap_sign;
                      Ok(json)
                  })
              })
          })
      })
      .map_err(|e| {
          println!("User fetch error: {:?}", e);
          e
      })
      .ok();

@Ichoran
Copy link

Ichoran commented Dec 9, 2018

The early-exit answers with ? are the same direction as I would go. I generally like to handle my errors as they come up, not save them for later, because all the intervening stuff is irrelevant for the errors. I haven't conducted benchmarking to know whether there is a performance penalty for the (implicit) double-testing using this approach, but if there is a penalty it should be small. So:

let mut res = req.map_err(|e| println!("User fetch error: {:?}", e)).ok()?;
let text = &res.text().ok()?;
let ap_sign = serde_json::from_str::<ApSignature>(text).ok()?;
let mut json = serde_json::from_str::<CustomPerson>(text).ok()?;
json.custom_props = ap_sign;
Some(json)

@aledomu
Copy link

aledomu commented Dec 9, 2018

I haven't conducted benchmarking to know whether there is a performance penalty for the (implicit) double-testing using this approach, but if there is a penalty it should be small.

and_then is basically a match expression that calls the passed function with the value of T if self is Ok(T) and bypasses self if it is Err(E), so you don't avoid anything there.

The and_then example doesn't work very well here because the value extraction can't be done in a fully stream-like fashion. To work around that without creating new variables (which is useless in itself) you have to do all that ugly indenting stuff that makes the code more difficult to read. The only thing you gain with that approach is not calling ok() multiple times, but again, I think the real solution is to change the return type of the function.

BTW I don't think losing information about Err is a good idea, unless you are micro-optimizing hard on memory usage and transfers for a very good reason.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment