Rust:在Mutex中封装BufRead,同时仍然实现BufRead



我需要构造一个类型,可以从库中传递给以下函数。

pub fn read_write_pair<R, W>(read: R, write: W) -> Term
where
R: BufRead + Debug + Send + 'static,
W: Write + AsRawFd + Debug + Send + 'static,
{
// details elided...
}

此外,我希望能够为我的测试操作readwrite。具体来说,我希望能够在没有任何内容的情况下构建这两个实例,将它们传递给这个函数,然后用字母设置库将读取的内容并提取它所写的内容。

这就是我对将用于read侧的Input类型的了解:

#[derive(Debug)]
pub struct Input {
prepared_content: Arc<Mutex<Cursor<Vec<u8>>>>,
}
impl Clone for Input {
fn clone(&self) -> Self {
Self {
prepared_content: Arc::clone(&self.prepared_content),
}
}
}
impl Input {
fn new() -> Self {
Self {
prepared_content: Default::default(),
}
}
fn append(&mut self, content: &str) {
let mut cursor = self.prepared_content.lock().unwrap();
cursor.get_mut().extend_from_slice(content.as_bytes());
}
}
impl Read for Input {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.prepared_content.lock().unwrap().read(buf)
}
fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
self.prepared_content.lock().unwrap().read_exact(buf)
}
}
impl BufRead for Input {
fn fill_buf(&mut self) -> std::io::Result<&[u8]> {
let mut content = self.prepared_content.lock().unwrap();
content.fill_buf()
}
fn consume(&mut self, amt: usize) {
self.prepared_content.lock().unwrap().consume(amt)
}
}

由内而外:

  • Vec<u8>是要读取的内容
  • Cursor使其成为BufRead
  • 当我想添加更多要读取的内容时,Mutex允许内部可变。它还使类型SendSync
  • Arc让我拥有多个所有者——我的测试函数和库本身

问题来自BufReadfill_buff:它返回的Result<&[u8]>将比MutexGuard本身更长。Cell会给我同样的内部可变性,但它不是发送/同步,我怀疑Cursor是复制。

我还有其他策略可以尝试吗?

从根本上讲,不可能将&[u8]获取到共享的内部可变缓冲区,因为这将允许在存在不可变引用的情况下进行突变。(作为这个规则边界上的一个例子:Cell::get_mut允许获得引用,但需要&mut到Cell,从而确保Cell当前不共享。(

想到的一件简单的事情是,传递一个BufReader<Input>,而不是为Input实现BufRead。然后,您仍然可以从外部提供要读取的字节,但不负责缓冲区。然而,这可能读得太多了。如果这对您不起作用,您将不得不使用内部不可变的缓冲区来实现BufRead,也就是

#[derive(Debug)]
pub struct Input {
prepared_content: Arc<Mutex<Cursor<Vec<u8>>>>,
buffer: Vec<u8>,
}

并且该实现根据需要将字节从CCD_ 24传输到CCD_。

这种方法意味着您不能从测试代码中交换出缓冲区的内容,但也不应该这样做,因为这违反了BufRead实现将保持其所提供的缓冲字节不变的合理预期,直到调用方处理完它们(通过调用consume()(。

最新更新