当我知道没有更多对其当前内容的引用时,如何改变切片?

How can I mutate a slice when I know that there are no more references to its current content?

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

由于 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
    }
}

playground

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`

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

然而,这里的示例 compiles successfully (playground)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);
    }
}