'Cannot call method because of unsatisfied trait bounds

I'm trying to implement parts of the minecraft protocol (https://wiki.vg/). I've successfully implemented a decoder to decode packets. But I'm stuck with the encoding part. The thing is that the minecraft protocol uses "minecraft varints" (https://wiki.vg/Protocol#VarInt_and_VarLong) and I want to have methods to write data as varints.

So my goal is to have a trait named Encoder with these methods:

    fn write_var_int(&mut self, value: i32) -> Result<(), error::EncodeError>;
    fn write_var_long(&mut self, value: i64) -> Result<(), error::EncodeError>;
    fn write_string(&mut self, value: &str) -> Result<(), error::EncodeError>;

At the moment, I've only written the code for the first method:

fn write_var_int(&mut self, mut value: i32) -> Result<(), error::EncodeError> {
loop {
            let mut byte = (value & 0b01111111) as u8;

            if byte == 0 {
                self.write_u8(byte).unwrap();
                break;
            }

            self.write_u8(byte | 0b10000000).unwrap();
            value = value >> 7;
        }
Ok(())
}

In main.rs I import the module Encoder and I try to use it on a cursor :

let test = [0; 17];
let mut wrt = Cursor::new(test);
wrt.write_var_int(packet.id);

But I get these compilation errors:

error[E0599]: the method `write_var_int` exists for struct `std::io::Cursor<[{integer}; 17]>`, but its trait bounds were not satisfied
  --> src/main.rs:57:37
   |
57 | ...                   wrt.write_var_int(packet.id);
   |                           ^^^^^^^^^^^^^ method cannot be called on `std::io::Cursor<[{integer}; 17]>` due to unsatisfied trait bounds
   |
  ::: /home/clement/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/io/cursor.rs:75:1
   |
75 | pub struct Cursor<T> {
   | --------------------
   | |
   | doesn't satisfy `std::io::Cursor<[{integer}; 17]>: Encoder`
   | doesn't satisfy `std::io::Cursor<[{integer}; 17]>: std::io::Write`
   |
note: the following trait bounds were not satisfied because of the requirements of the implementation of `Encoder` for `_`:
      `std::io::Cursor<[{integer}; 17]>: std::io::Write`
  --> src/protocol/encoder.rs:12:16
   |
12 | impl<W: Write> Encoder for W {
   |                ^^^^^^^     ^

warning: unused import: `protocol::encoder::Encoder`
  --> src/main.rs:11:5
   |
11 | use protocol::encoder::Encoder;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^

For more information about this error, try `rustc --explain E0599`.
warning: `eupim` (bin "eupim") generated 2 warnings
error: could not compile `eupim` due to previous error; 2 warnings emitted

I don't understand why the import of the Encoder module is marked as unused, and how to fix these errors.

I'll be pleased to have hints on how to fix this.

Thanks!



Solution 1:[1]

I tried to turn the code in your question into a minumal reproducible example:

use std::io::{Cursor, Write};
use std::slice;

mod error {
    #[derive(Debug)]
    pub enum EncodeError { }
}

trait Encoder {
    fn write_u8(&mut self, value: u8) -> Result<(), error::EncodeError>;
    fn write_var_int(&mut self, value: i32) -> Result<(), error::EncodeError>;
}

impl<W: Write> Encoder for W {
    fn write_u8(&mut self, value: u8) -> Result<(), error::EncodeError> {
        self.write(slice::from_ref(&value)).unwrap();
        Ok(())
    }

    fn write_var_int(&mut self, mut value: i32) -> Result<(), error::EncodeError> {
        loop {
            let mut byte = (value & 0b01111111) as u8;
    
            if byte == 0 {
                self.write_u8(byte).unwrap();
                break;
            }
    
            self.write_u8(byte | 0b10000000).unwrap();
            value = value >> 7;
        }
        Ok(())
    }
}

fn main() {
    let test = [0; 17];
    let mut wrt = Cursor::new(test);
    wrt.write_var_int(3);
}

This produces the error:

   Compiling playground v0.0.1 (/playground)
error[E0599]: the method `write_var_int` exists for struct `std::io::Cursor<[{integer}; 17]>`, but its trait bounds were not satisfied
  --> src/main.rs:39:9
   |
39 |       wrt.write_var_int(3);
   |           ^^^^^^^^^^^^^ method cannot be called on `std::io::Cursor<[{integer}; 17]>` due to unsatisfied trait bounds
   |
note: the following trait bounds were not satisfied because of the requirements of the implementation of `Encoder` for `_`:
      `std::io::Cursor<[{integer}; 17]>: std::io::Write`
  --> src/main.rs:14:16
   |
14 | impl<W: Write> Encoder for W {
   |                ^^^^^^^     ^

For more information about this error, try `rustc --explain E0599`.
error: could not compile `playground` due to previous error

The problem here is that we've got a Cursor<[{integer}; 17]>, but Write is only implemented for a Cursor<&mut [u8]>, where &mut [u8] is a mutable reference to a u8 slice.

This makes sense if you think about it: Cursor wraps an in-memory buffer, but there's no need for it to take ownership of it.

So let's make sure we're passing a mutable slice to our Cursor:

fn main() {
    let mut test = [0u8; 17];
    let mut wrt = Cursor::new(&mut test[..]);
    wrt.write_var_int(3);
}

This compiles as expected.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1