Unable to infer enough type information about `_`, but i defined


#1

Hi, nice to me you. I am a new man using rust to write web project. I try to archive a JWT, but i meet a probleam when i write a Token trait.

My mind is write a common trait for every string which is Tokenable. So i can use tokenString.decode() to get a decode token that include header and claims.

But the error occur in signature method, i have no idea for solving this error. Are there someone guide me to solve this? Thank you very much.

pub trait Tokenable<B> {
    type DecodeToken;

    fn decode(&self, secret: &[u8], algorithm: Algorithm) -> Result<Self::DecodeToken, Error>;
    fn signature(&self, secret: &[u8], algorithm: Algorithm) -> String;
}


impl<B> Tokenable<B> for String where B: Base64able{
    type DecodeToken = DeToken<B>;

    fn decode(&self, secret: &[u8], algorithm: Algorithm) -> Result<Self::DecodeToken, Error> {
        let token_data: Vec<&str> = self.rsplit('.').collect();
        if token_data.len() != 3 {
            return Err(Error::InvalidToken);
        }

        let header: Header = try!(Header::from_base64(token_data[3]));
        let claims: B = try!(B::from_base64(token_data[2]));
        let sign = token_data[1];

        // Validate algorithm
        if header.alg != algorithm {
            return Err(Error::InvalidAlgorithm);
        }

        // Validate signature
        let payload: String = [token_data[3], token_data[2]].join(".");
        let re_sign: String = payload.signature(secret, header.alg);
        if re_sign != sign {
            return Err(Error::InvalidSignature);
        }

        let de_token = DeToken::new(header, claims);
        Ok(de_token)
    }

    fn signature(&self, secret: &[u8], algorithm: Algorithm) -> String {
        fn crypt<D: Digest>(digest: D, payload: &str, secret: &[u8]) -> String {
            let mut hmac = Hmac::new(digest, secret);
            hmac.input(payload.as_bytes());
            hmac.result().code().to_base64(base64::URL_SAFE)
        }

        match algorithm {
            Algorithm::HS256 => crypt(Sha256::new(), self, secret),
            Algorithm::HS384 => crypt(Sha384::new(), self, secret),
            Algorithm::HS512 => crypt(Sha512::new(), self, secret),
        }
    }}

This is error showing: :frowning:

src/lib.rs:132:39: 132:68 error: unable to infer enough type information about _; type annotations or generic parameter binding required [E0282]
src/lib.rs:132 let re_sign: String = payload.signature(secret, header.alg);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/lib.rs:132:39: 132:68 help: run rustc --explain E0282 to see a detailed explanation
error: aborting due to previous error
Could not compile jsonwebtoken.


#2

You need to surround your code in fences

```rust
like this
```

#3

The problem is that you’re trying to call the signature method on a String and not Tokenable. payload is obviously of type String in your code:

let payload: String = [token_data[3], token_data[2]].join(".");
let re_sign: String = payload.signature(secret, header.alg);

It must be some type that implements Tokenable to have the decode method.


#4

Thank u for your good advice


#5

Hi, thanks, but i impl tokenable for String :grin:


#6

I couldn’t see that in the code block you posted previously without formatting.


#7

The compiler doesn’t have enough information to infer the B parameter for the Tokenable<B> trait. You can specify the parameter like this:

let re_sign = Tokenable::<Foo>::signature(&payload, secret, header.alg);

where Foo is some type that implements the Base64able trait.


#8

Specifically, I think you want to pass the B parameter in that case, as in:

let re_sign = <String as Tokenable<B>>::signature(&payload, secret, header.alg);

#9

Hi, thanks. :slight_smile:

In my design, i impl tokenable to string, the payload also is string type, so i call payload.signature()

to sign directly, so the method need two param , secret and header.alg.

In this case, how can i solve the issuse?


#10

hi , thanks very much, this my mind


#11

Method calls are actually just sugar for longer functions like the ones we posted. So this:

payload.signature(secret, header.alg)

means the same thing as:

<String as Tokenable<_>>::signature(&payload, secret, header.alg)

Note that &payload is in the position of the &self parameter in the definition of the method.

The problem is that the compiler can’t figure out that you want to treat it as a tokenable of the same type B as the impl block, so you need to specify that. It doesn’t seem matter here what type B is, but the compiler also doesn’t know that it doesn’t matter. An easy way to tell the compiler what type to use is to use the longer form of the function.


#14

Hi, Mr withoutboats. I change my tokenable trait. before my tokenable trait impl for String only,

so if i has a str like “abcdefg”, i cant use decode() method in this str. So i want to tokenable impl for

str, string and all like string type.

like below.

pub trait Tokenable<B> {
    fn decode(&self, secret: &[u8], algorithm: Algorithm) -> Result<DeToken<B>, Error>;
    fn signature(&self, secret: &[u8], algorithm: Algorithm) -> String;
}


impl<B, T> Tokenable<B> for T where B: Base64able, T: AsRef<str> {
    fn decode(&self, secret: &[u8], algorithm: Algorithm) -> Result<DeToken<B>, Error> {
        let token_data: Vec<&str> = self.rsplit('.').collect();
        if token_data.len() != 3 {
            return Err(Error::InvalidToken);
        }

        let header: Header = try!(Header::from_base64(token_data[3]));
        let claims: B = try!(B::from_base64(token_data[2]));
        let sign = token_data[1];

        // Validate algorithm
        if header.alg != algorithm {
            return Err(Error::InvalidAlgorithm);
        }

        // Validate signature
        let payload: String = [token_data[3], token_data[2]].join(".");
        let re_sign: String = <String as Tokenable<B>>::signature(&payload, secret, header.alg);
        if re_sign != sign {
            return Err(Error::InvalidSignature);
        }

        let de_token = DeToken::new(header, claims);
        Ok(de_token)
    }

    fn signature(&self, secret: &[u8], algorithm: Algorithm) -> String {
        fn crypt<D: Digest>(digest: D, payload: &str, secret: &[u8]) -> String {
            let mut hmac = Hmac::new(digest, secret);
            hmac.input(payload.as_bytes());
            hmac.result().code().to_base64(base64::URL_SAFE)
        }

        match algorithm {
            Algorithm::HS256 => crypt(Sha256::new(), self, secret),
            Algorithm::HS384 => crypt(Sha384::new(), self, secret),
            Algorithm::HS512 => crypt(Sha512::new(), self, secret),
        }
    }
}

but i meet a error:

Compiling jsonwebtoken v1.0.0 (file:///Users/xiongbingchao/Developer/rust-jwt)
src/main.rs:107:42: 107:53 error: no method named rsplit found for type &T in the current scope
src/main.rs:107 let token_data: Vec<&str> = self.rsplit(’.’).collect();
^~~~~~~~~~~
src/main.rs:107:42: 107:53 help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item rsplit, perhaps you need to implement it:
src/main.rs:107:42: 107:53 help: candidate #1: core::str::StrExt


#15

You have to call as_ref() every time you want to use a str method on T because that’s what converts T to a str.