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

Update Serde to 1.0 #28

Merged
merged 4 commits into from
Apr 22, 2017
Merged

Update Serde to 1.0 #28

merged 4 commits into from
Apr 22, 2017

Conversation

mike-engel
Copy link
Contributor

@mike-engel mike-engel commented Apr 21, 2017

This is PR updates serde to 1.0. The README and Cargo file have been updated to use 1.0. This will close out #27.

@mike-engel
Copy link
Contributor Author

mike-engel commented Apr 21, 2017

As of right now, there are two lifetime issues here and here. I've tried using str::from_utf8, but that's no good either since then decoded goes out of scope too quick.

@Keats I'll keep trying here, but I don't think I have enough Rust experience with how to combat these two lifetime issues. If you have any ideas, let me know!

Fixed!

``` error: `s` does not live long enough --> src/serialization.rs:31:18 | 31 | Ok(from_str(&s)?) | ^ does not live long enough 32 | } | - borrowed value only lives until here | note: borrowed value must be valid for the lifetime 'a as defined on the body at 27:85... --> src/serialization.rs:27:86 | 27 | pub fn from_jwt_part<'a, B: AsRef, T: Deserialize<'a>>(encoded: B) -> Result { | ______________________________________________________________________________________^ starting here... 28 | | let decoded = base64::decode_config(encoded.as_ref(), base64::URL_SAFE_NO_PAD)?; 29 | | let s = String::from_utf8(decoded)?; 30 | | 31 | | Ok(from_str(&s)?) 32 | | } | |_^ ...ending here

error: s does not live long enough
--> src/serialization.rs:41:31
|
41 | let claims: T = from_str(&s)?;
| ^ does not live long enough
...
44 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the body at 37:40...
--> src/serialization.rs:37:41
|
37 | -> Result<(T, Map<String, Value>)> {
| _________________________________________^ starting here...
38 | | let decoded = base64::decode_config(encoded.as_ref(), base64::URL_SAFE_NO_PAD)?;
39 | | let s = String::from_utf8(decoded)?;
40 | |
41 | | let claims: T = from_str(&s)?;
42 | | let map: Map<_, > = from_str(&s)?;
43 | | Ok((claims, map))
44 | | }
| |
^ ...ending here

</details>

@Keats
Copy link
Owner

Keats commented Apr 22, 2017

Thanks!
Actually I just noticed there is a https://docs.serde.rs/serde/de/trait.DeserializeOwned.html trait that might be more what we want since as a library we don't really know how the end struct is going to be used.

Is that how it's meant to be used @dtolnay (sorry for the random ping)?

@dtolnay
Copy link

dtolnay commented Apr 22, 2017

I always appreciate a ping! Yes, both from_jwt_part and from_jwt_part_claims require T: DeserializeOwned because they are deserializing from the base64-decoded data so they shouldn't be allowed to borrow anything (the base64-decoded data goes out of scope when the function returns).

I will leave a few review comments as well.

src/lib.rs Outdated
algorithm: Algorithm,
validation: &Validation)
-> Result<TokenData<T>>
where for<'a> T: Deserialize<'a>
Copy link

Choose a reason for hiding this comment

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

This would be more readable as T: DeserializeOwned. This function requires that T can deserialize without borrowing any data because the string it is deserialized from is thrown away before this function returns.

use header::Header;


/// The return type of a successful call to decode
#[derive(Debug)]
pub struct TokenData<T: Deserialize> {
pub struct TokenData<T>
where for<'a> T: Deserialize<'a>
Copy link

Choose a reason for hiding this comment

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

This bound should not be here. Structs in Rust should never have trait bounds. Trait bounds are for behavior.

impl<T> Data<T> where T: Behavior { /* behavior, okay */ }

fn behave<T>() where T: Behavior { /* also behavior, also okay */ }

struct Data<T> where T: Behavior { /* don't do this */ }

The only exception is things like Cow that use associated types to define data.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the clarification. If it's not obvious, I'm new to Rust, and this result was me fighting with lifetime errors from the compiler 😞

Copy link

Choose a reason for hiding this comment

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

I filed https://github.com/Manishearth/rust-clippy/issues/1689 to catch this case with a warning in Clippy. Apparently even the standard library does it wrong sometimes!

src/crypto.rs Outdated
hmac::sign(&signing_key, signing_input.as_bytes()).as_ref(),
base64::URL_SAFE_NO_PAD
))
Ok(base64::encode_config(hmac::sign(&signing_key, signing_input.as_bytes()).as_ref(),
Copy link

Choose a reason for hiding this comment

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

Next time please make whitespace changes in a separate commit. They makes it hard to find and review the thing you are actually changing.

Copy link
Owner

Choose a reason for hiding this comment

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

Agreed on that, @mike-engel can you revert all the formatting changes for now?
Is it rustfmt using the latest config? I thought it would be more block indented than that

Copy link

Choose a reason for hiding this comment

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

Block style is currently recommended by the fmt-rfc folks but not the default in rustfmt. This is the settings they recommend.

Copy link

Choose a reason for hiding this comment

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

More official source I guess: here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, sorry about that! Turns out my rustfmt was old. Would you prefer me to avoid rustfmt altogether, or add a config like the two linked from serde & rustmft?

Copy link
Owner

Choose a reason for hiding this comment

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

Avoid it for now please, we can run it later

@mike-engel
Copy link
Contributor Author

Ok, updated now with DeserializedOwned, which made everything much better. Sorry I didn't see that in the docs before, and thanks to @dtolnay for the suggestions, clarifications, work the work on serde 😄

Tests and benchmarks run fine. If there's anything else you'd like me to fix/edit/add, let me know.

@@ -10,7 +10,7 @@ use header::Header;

/// The return type of a successful call to decode
#[derive(Debug)]
pub struct TokenData<T: Deserialize> {
pub struct TokenData<T: DeserializeOwned> {
Copy link

Choose a reason for hiding this comment

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

This bound should be removed: just pub struct TokenData<T> { ... }. See https://github.com/Manishearth/rust-clippy/issues/1689.

@Keats
Copy link
Owner

Keats commented Apr 22, 2017

Thanks to both of you!

@Keats Keats merged commit d8439b1 into Keats:master Apr 22, 2017
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.

3 participants