rusttraitstype-bounds

the method `fold` exists for reference `&[T]`, but its trait bounds were not satisfied, I don't understand the given bounds in question


So I'm building a chip-8 CPU emulator and to make copying data into the memory easier I created the following two methods:

pub struct CPU {
    // ... other unrelated fields
    pub memory: [u8; 0x1000],
}

impl CPU {
    pub fn raw_copy_to_mem(&mut self, loc: usize, data: &[u8]) {
        data.chunks(2).fold(loc, |loc, bytes| {
            self.raw_add_to_mem(loc, *bytes.first().unwrap(), *bytes.last().unwrap())
        });
    }

    pub fn raw_add_to_mem(&mut self, loc: usize, high: u8, low: u8) -> usize {
        self.memory[loc] = high; self.memory[loc + 1] = low;
        loc + 2
    }
}

Now this works for this for example:

fn make_cpu() -> processor::CPU {

   processor::CPU {
        // ... other unrelated fields
        memory: [0; 0x1000],
    }
}
#[test]
fn test_raw_memory_copy() {
    let mut cpu = make_cpu();

    let add_twice: [u8; 6] = [
        0x80, 0x14,
        0x80, 0x14,
        0x00, 0xEE,
    ];

    cpu.raw_copy_to_mem(0x100 , &add_twice);

    assert_eq!(cpu.memory[0x100..0x106], add_twice);

}

Now to make doing OpCodes easier I have the following struct and functions:

#[derive(Debug, Clone, Copy)]
pub struct OpCode(u8, u8);

impl OpCode {
    pub fn high_byte(&self) -> u8 {
        self.0
    }

    pub fn low_byte(&self) -> u8 {
        self.1
    }
}

impl From<OpCode> for u16 {
    fn from(c: OpCode) -> Self {
        (c.0 as u16) << 8 | c.1 as u16
    }
}

impl From<&OpCode> for u16 {
    fn from(c: &OpCode) -> u16 {
        c.into()
    }
}

impl OpCode {
    pub fn add(h: u8, l: u8) -> Self {
        Self (0x8 << 4 | h, (l << 4) | 4)
    }
}

And the following CPU function also works great:

impl CPU {
    pub fn add_to_mem(&mut self, loc: usize, oc: &OpCode) -> usize {
        self.memory[loc] = oc.high_byte(); self.memory[loc + 1] = oc.low_byte();
        loc + 2
    }
}

The problem occurs when I try to add a copy_to_mem() function for the OpCode struct:

impl CPU {
    pub fn copy_to_mem(&mut self, loc: usize, data: &[OpCode]) {
        data.fold(loc, |loc, opcode| {
            self.add_to_mem(loc, opcode)
        });
    }
}

I get the following error that I only vaguely understand:

error[E0599]: the method `fold` exists for reference `&[OpCode]`, but its trait bounds were not satisfied
  --> src/processor.rs:21:14
   |
21 |         data.fold(loc, |loc, bytes| {
   |              ^^^^ method cannot be called on `&[OpCode]` due to unsatisfied trait bounds
   |
   = note: the following trait bounds were not satisfied:
           `&[OpCode]: Iterator`
           which is required by `&mut &[OpCode]: Iterator`
           `[OpCode]: Iterator`
           which is required by `&mut [OpCode]: Iterator`

I get that it's saying that whilst there is a fold() function & that it can't call it because some trait bounds weren't satisfied so it can't call it but it doesn't state what those bounds are in a way that I can understand.

So, could someone explain what is going on, and how to fix?


Solution

  • The error message is misleading: the problem is that you're trying to use a slice as an iterator, but it isn't. To obtain an iterator for the slice, call it's iter() method (or iter_mut() for mutable iterator).

    pub fn copy_to_mem(&mut self, loc: usize, data: &[OpCode]) {
        data.iter().fold(loc, |loc, bytes| {
            self.add_to_mem(loc, bytes.high_byte())
        });
    }
    

    Note that it'll still error with:

    error[E0308]: mismatched types
      --> src/lib.rs:60:34
       |
    60 |             self.add_to_mem(loc, bytes.high_byte())
       |                                  ^^^^^^^^^^^^^^^^^ expected `&OpCode`, found `u8`
    

    Because add_to_mem expects &OpCode but while bytes is indeed &OpCode bytes.high_byte() is u8.