Rust 零拷贝生存期处理

Rust 零拷贝生存期处理,rust,lifetime,borrow-checker,Rust,Lifetime,Borrow Checker,我正在尝试实现一种零拷贝机制,用于Rust中的实时数据处理。 为了说明我的问题,我准备了以下示例: use std::io; pub trait Producer<T> { fn produce(&self) -> Result<T, ()>; } pub trait Consumer<T> { fn consume(&self, t: T); } pub trait Source<T> : Produc

我正在尝试实现一种零拷贝机制,用于Rust中的实时数据处理。 为了说明我的问题,我准备了以下示例:

use std::io;

pub trait Producer<T> {
    fn produce(&self) -> Result<T, ()>;
}

pub trait Consumer<T> {
    fn consume(&self, t: T);
}

pub trait Source<T> : Producer<T> {
    fn push(&self, t: T) -> io::Result<()>;
}

pub trait Sink<T> : Consumer<T> {
    fn pull(&self) -> io::Result<T>;
}

pub struct SyncSource<T> {
    pub producer: Option<Box<dyn Fn() -> T>>,
}

impl<T> SyncSource<T> {
    pub fn new() -> SyncSource<T> {
        SyncSource {
            producer: None,
        }
    }
}

impl<T> Producer<T> for SyncSource<T> {
    fn produce(&self) -> Result<T, ()> {
        match &self.producer {
            Some(func) => Ok((*(func))()),
            None => Err(()),
        }
    }
}

impl<T> Source<T> for SyncSource<T> {
    fn push(&self, t: T) -> io::Result<()> {
        // do something useful
        Ok(())
    }
}

pub struct Frame<'a> {
    pub buf: &'a [u8],
}

pub struct Capture {
    buf: Vec<u8>,
}

impl Capture {
    pub fn add(&mut self, val: u8) {
        self.buf.push(val);
    }

    pub fn read(&self) -> Frame {
        Frame {
            buf: &self.buf[..],
        }
    }
}

fn main() {
    let mut capture = Capture {
        buf: Vec::new(),
    };

    let source: SyncSource<Frame> = SyncSource::new();

    // immutable borrow of 'capture'
    let frame = capture.read();

    source.push(frame);

    // mutable borrow of 'capture'
    capture.add(1); // ERROR
}
使用std::io;
酒吧特征制作人{
fn产生(和自我)->结果;
}
酒吧特质消费者{
fn消费(和自我,t:t);
}
资料来源:制作人{
fn push(&self,t:t)->io::Result;
}
酒吧:消费者{
fn pull(&self)->io::Result;
}
发布结构同步源{
酒吧制作人:选项>,
}
impl同步源{
pub fn new()->SyncSource{
同步源{
制片人:没有,
}
}
}
同步源的impl生产者{
fn生成(&self)->结果{
比赛与自我制作人{
Some(func)=>Ok((*(func))(),
无=>Err(()),
}
}
}
同步源的impl源{
fn推送(&self,t:t)->io::结果{
//做些有用的事
好(())
}
}
pub结构框架{
框架{
buf:&self.buf[…],
}
}
}
fn main(){
让mut捕获=捕获{
buf:Vec::new(),
};
让source:SyncSource=SyncSource::new();
//“捕获”的不变借用
让frame=capture.read();
源。推(帧);
//“捕获”的可变借用
capture.add(1);//错误
}
。。这当然会产生借用检查器错误:

error[E0502]: cannot borrow `capture` as mutable because it is also borrowed as immutable
   --> src/bin/so.rs:212:5
    |
208 |     let frame = capture.read();
    |                 ------- immutable borrow occurs here
...
212 |     capture.add(1);
    |     ^^^^^^^^^^^^^^ mutable borrow occurs here
213 | }
    | - immutable borrow might be used here, when `source` is dropped and runs the destructor for type `SyncSource<'_, Frame<'_>>`
error[E0502]:无法将'capture'作为可变项借用,因为它也是作为不可变项借用的
-->src/bin/so.rs:212:5
|
208 | let frame=capture.read();
|------此处发生不可变借用
...
212 |捕获。添加(1);
|^^^^^^^^^^^^^^^^^^^^此处发生可变借用
213 | }
|-当删除'source'并运行'SyncSource>`
我理解
push(frame)
不能在
capture.add(1)
几行之后需要可变引用的同一范围内具有不变引用

我试图实现的是
push(frame)
能够对切片做一些有用的事情(如果必要的话,可以将其复制到一个Vec中),但可能不会对其做任何事情

基本上,我需要确保调用
push(frame)
后,
frame
的生存期结束。然后,这将释放对
Capture
的借用引用,并且
Capture.add(1)
调用将成功地获得适当的可变引用

我的零拷贝要求不将切片复制到Vec中,然后将新缓冲区交给
push(…)
。 我错过了什么?可能是一些明确的生命周期注释?

如何修复它 创建一个新块,以确保在变异
捕获之前删除不可变借用(
):

let mut capture=capture{
buf:Vec::new(),
};
{
让source:SyncSource=SyncSource::new();
//“捕获”的不变借用
让frame=capture.read();
//已移到`源'`
源。推(帧);
//‘source’掉在这里了
}
//“捕获”的可变借用
捕获。添加(1);
为什么NLL没有帮助 应使用(NLL)修复此问题。但是,NLL不适用于实现trait的类型,因为
Drop
总是在值的词法范围末尾调用,以实现向后兼容性

由于
SyncSource
包含一个trait对象(
dyn Fn()->T
),该对象可能实现
Drop
,因此在这种情况下阻止NLL。在中,您可以看到,由于NLL,删除trait对象可以修复错误

但是我想在一个循环中访问
源代码
捕获
! 然后可变借用和不可变借用被交错,这意味着Rust无法在编译时验证所有权规则

您可以通过使用来解决这个问题,这样可以确保在运行时维护所有权规则。这可以这样实现:

使用std::cell::{RefCell,Ref};
pub结构框架,
}
发布结构捕获{
buf:RefCell,
}
impl捕获{
发布fn添加(&self,val:u8){
self.buf.borrow_mut().push(val);
}
发布fn读取(&self)->帧{
框架{
buf:self.buf.borrow(),
}
}
}

我认为在这种情况下,只要让
让mut owner=…
就可以解决编译错误。NLL(非词汇生存期)应该足够让您的示例按预期工作:对不起,我不小心上传了错误的代码。我现在用适当的例子更新了这篇文章。如果你把源、汇、帧放在一个单独的作用域中会发生什么?不幸的是,这不是一个选择,因为我还有一段时间。。在主函数中循环,该函数读取帧,将其沿管道向下推,然后修改捕获对象。例如:。这段代码非常抽象,很难修复,因为我不知道哪些修复可能合适或不合适。我猜你的答案没有坚持,因为你不再使用
&'a mut self