I have a trait for objects that can provide bytes from some index. These could be files, processes being ptraced, caches over other byte providers, etc.:
use std::result::Result;
use std::io::Error;
trait ByteProvider {
fn provide_bytes(&mut self, index: usize, dest: &mut[u8]) -> Result<usize, Error>;
}
struct ZeroProvider { }
impl ByteProvider for ZeroProvider {
fn provide_bytes(&mut self, _index: usize, dest: &mut[u8]) -> Result<usize, Error> {
dest.iter_mut().for_each(|e| *e = 0);
Ok(dest.len())
}
}
I also have a set of widgets working on any generic type implementing the ByteProvider trait:
struct HexDump<T: ByteProvider> {
provider: T
}
struct Disassembler<T: ByteProvider> {
provider: T
}
impl<T: ByteProvider> HexDump<T> {
pub fn new(provider: T) -> Self { Self { provider } }
pub fn dump(&mut self) {
let mut bytes = [0; 16];
self.provider.provide_bytes(0, &mut bytes).unwrap();
println!("{}", bytes.iter().map(|e| format!("{:02x}", e)).collect::<Vec<String>>().join(" "));
}
}
impl<T: ByteProvider> Disassembler<T> {
pub fn new(provider: T) -> Self { Self { provider } }
pub fn disassemble(&mut self) {
println!("Disassembly");
}
}
This works fine:
fn main() {
let provider = ZeroProvider {};
let mut dumper = HexDump::new(provider);
dumper.dump();
}
...however, I would like multiple views into the same data:
fn main() {
let provider = ZeroProvider {};
let mut dumper = HexDump::new(provider);
let mut disassembler = Disassembler::new(provider);
dumper.dump();
disassembler.disassemble();
}
However this is of course not valid Rust, so I turned to reference counted smart pointers for help expecting this to work:
use std::rc::Rc;
fn main() {
let provider = Rc::new(ZeroProvider {});
let mut dumper = HexDump::new(Rc::clone(&provider));
let mut disassembler = Disassembler::new(Rc::clone(&provider));
dumper.dump();
disassembler.disassemble();
}
However, the compiler does not like this:
27 | impl<T: ByteProvider> HexDump<T> {
| ^^^^^^^^^^^^ ----------
| |
| unsatisfied trait bound introduced here
...
error[E0599]: the method `dump` exists for struct `HexDump<Rc<_, _>>`, but its trait bounds were not satisfied
--> src/main.rs:48:12
|
19 | struct HexDump<T: ByteProvider> {
| ------------------------------- method `dump` not found for this struct
...
48 | dumper.dump();
| ^^^^ method cannot be called on `HexDump<Rc<_, _>>` due to unsatisfied trait bounds
...with similar errors for Disassembler and I cannot decipher that. What am I missing?
I think the problem is that Rc does not implement my trait but doesn't it expose its nested objects interface?
I would like for the widgets (HexDump and Disassembler) not to be aware that their byte providers are being shared if possible. Can this be accomplished?
impl<T> Provider for Rc<T> where T: Provider, but then you'll run into the issue thatProvider::provide_bytes()requires&mut self, whichRccannot give. Perhaps you could write a wrapper that uses interior mutability (RefCell) to achieve that.provide_bytesto take a&selfand useHexDump<ZeroProvider&>.