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?
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
.