Hello,
I am currently working on a library, that allows you to create a "SubCursor" from structs, that implement Read, Write or Seek. It makes it possible to have a Reader, that only has access to parts of the Cursor.
Most of the coding is already done and the next step is to make it conform to the Api-Guidelines before I start documenting the codebase.
The core concept is, that the user passes a reference of a RefCell,
struct SubCursor<C> {
cursor: &'s RefCell<C>
}
impl<'s, C> SubCursor<'s, C> {
pub fn new(cursor: &'s RefCell<C>) {
Self {
cursor: cursor,
}
}
}
that wraps around the Cursor to the struct and I want to make it generic, because there exist multiple different implementations of RefCells like PinCell, AtomicRefCell or QCell and I only care about the .borrow_mut()
function.
I searched a bit in the Std-Library and found the BorrowMut trait and thought, I found a solution for the problem, but it seems to be for such cases:
fn sample(value: &mut String);
fn sample<T: BorrowMut>(value: D);
Test Code
I wrote some test code that covers exactly, what I want to do:
use std::io::prelude::*;
use std::borrow::BorrowMut;
use std::cell::RefCell;
use std::io::Cursor;
type Result<T> = std::result::Result<T, Box<std::error::Error>>;
fn generic_function<'s, C, T>(value: &'s T) -> Result<Vec<u8>>
where
C: Read + Seek,
T: BorrowMut<C>
{
let mut result = [0; 4];
value.borrow_mut().read(&mut result)?;
Ok(result.to_vec())
}
fn specific_function<'s, C>(value: &'s RefCell<C>) -> Result<Vec<u8>>
where
C: Read + Seek,
{
let mut result = [0; 4];
value.borrow_mut().read(&mut result)?;
Ok(result.to_vec())
}
fn main() {
let data = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let cursor = RefCell::new(Cursor::new(data));
let result = specific_function(&cursor);
// Ok([0, 1, 2, 3])
println!("{:?}", result);
}
The "specific_function" works as expected, but the "generic_function" gives a compiler error.
error[E0599]: no method named `read` found for type `&mut &'s T` in the current scope
--> src/main.rs:14:24
|
14 | value.borrow_mut().read(&mut result)?;
| ^^^^
|
= note: the method `read` exists but the following trait bounds were not satisfied:
`&mut &'s T : std::io::Read`
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `read`, perhaps you need to implement it:
candidate #1: `std::io::Read`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0599`.
error: Could not compile `hi`.
To learn more, run the command again with --verbose.
Other Options (not really future proof)
The other option, that I thought of would be to write a custom trait and implement it on each of the RefCell types manually (I didn't check if the code below works)
trait RefCellTrait {
fn borrow_mut(&self) -> RefMut<T>;
}
impl RefCellTrait for RefCell {}
impl RefCellTrait for PinCell {}
// ...
Or I could write an enum which contains all the types of RefCells
enum RefCellTypes<C> {
RefCell(RefCell<C>),
QCell(QCell<C>),
// ...
}
impl<C> From<RefCell<C>> for RefCellTypes<C> {
fn from(w: RefCell<C>) -> Self {
RefCellTypes::RefCell(w)
}
}
//...
The problem with these kinds of solutions is, that it's very specific and new implementations can't be used without adding them to my source code manually.
So before I continue experimenting with the BorrowMut trait I wanted to ask in the forum in the hope, that someone can help me out
Hava a nice day
Lucas