当我知道没有更多对其当前内容的引用时,如何改变切片?
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
}
}
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);
}
}
在没有堆的嵌入式设备上,我想解析输入数据并将找到的结果存储在输出切片中。我有一个 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
}
}
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);
}
}