1

在没有堆的嵌入式设备上,我想解析输入数据并将找到的结果存储在输出切片中。我有一个阅读器,它允许我获取当前可用的数据和一个解析器,它将输入数据与预期的格式相匹配,并将结果存储在Parsed::Values 的切片中,该切片可能包含对输入数据的引用。

由于 Rust 编译器发现可能存在对输入数据的引用,因此我不能多次更改数据缓冲区。由于我可以通过手动将输出切片重置为 来确保不再有引用Parsed::Unused,我认为重用缓冲区应该是安全的。如何在循环的每次迭代中改变输入缓冲区?

以下是我的最小示例,它说明了我的问题:

trait Reader {
    fn peek<'a>(&self, data: &'a mut [u8]) -> &'a [u8]; // copy currently available bytes from ringbuffer
    fn consume(&self, num: usize);                      // drop at the head of input queue
}

trait Parser {
    fn parse<'a>(&self, input: &'a [u8], parsed_value: &mut [Parsed<'a>]) -> Result<(), ()>;
}

enum Parsed<'a> {
    Unused,
    Value(&'a [u8]),
}

fn read_and_parse<'a>(
    reader: impl Reader,
    parser: impl Parser,
    data_buffer: &'a mut [u8],
    values: &mut [Parsed<'a>],
) {
    loop {
        for v in values.iter_mut() {
                                 // This block should ensure that no more
            *v = Parsed::Unused; // references are held into the buffer
        }                        // used in the previous iteration.
        let rx = reader.peek(data_buffer);
        if let Ok(()) = parser.parse(rx, values) {
            return;
        }
        reader.consume(1); // this could be replaced with smarter logic how to drop input bytes
    }
}

操场

error[E0499]: cannot borrow `*data_buffer` as mutable more than once at a time
  --> src/lib.rs:26:30
   |
15 | fn read_and_parse<'a>(
   |                   -- lifetime `'a` defined here
...
26 |         let rx = reader.peek(data_buffer);
   |                  ------------^^^^^^^^^^^-
   |                  |           |
   |                  |           mutable borrow starts here in previous iteration of loop
   |                  argument requires that `*data_buffer` is borrowed for `'a`
4

1 回答 1

-1

在许多情况下似乎有效的一件事是转换切片,它也可以用来改变生命周期。由于这通常是“非常不安全”,我个人尽量避免使用此功能,而是寻找不同的方法来解决我的问题。在许多情况下,这些甚至被证明是更清洁的。

然而,这里的示例成功编译(操场)transmute

trait Reader {
    fn peek<'a>(&self, data: &'a mut [u8]) -> &'a [u8];
    fn consume(&self, num: usize);
}

trait Parser {
    fn parse<'a>(&self, input: &'a [u8], parsed_value: &mut [Parsed<'a>]) -> Result<(),()>;
}

enum Parsed<'a> {
    Unused,
    Value(&'a [u8])
}

fn read_and_parse<'a>(reader: impl Reader, parser: impl Parser, data_buffer: &'a mut [u8], values: &mut [Parsed<'a>]) {
    loop {
        for v in values.iter_mut() { // This block should ensure that no more
            *v = Parsed::Unused;     // references are held into the buffer
        }                            // used in the previous iteration.
        let data_buffer = unsafe { core::mem::transmute(&mut *data_buffer) };
        let rx = reader.peek(data_buffer);
        if let Ok(()) = parser.parse(rx, values) {
            return;
        }
        reader.consume(1);
    }
}
于 2021-05-14T08:40:30.447 回答