I'm parsing a packet stream. Some packets are containers and hold other packets or containers. The result is a tree. For instance:
root
/ \
encrypted ...
data
|
compressed
data
|
literal data
To parse the packets, I have a method with the following signature:
impl Packet {
fn next(self) -> Result<(Packet, Option<Packet>, isize), io::Error>;
}
The return values are: the last packet, a packet parser for the new packet and the position of the new packet in the tree with respect to the old packet. Concretely, if the value is 0, they are siblings. If the value is 1, the
old packet is a container and the new packet is its first child. If the value is -1, the new packet is contained in the old packet's grandparent. The idea is illustrated below:
...
|
grandparent
| \
parent -1
| \
packet 0
|
1
When I deserialize the message all at once, I parse the packets in a loop. In each iteration of the loop, I insert a packet. Right now, each time I insert a packet into the tree, I walk from the root of the tree to the right container. I want to optimize this a bit. For instance, if the relative position is 0, the container is the same as the one that I inserted the last packet into (recall: they are siblings).
Here's what I'm currently doing (this works): Rust Playground
And here's what I want to do (this doesn't compile): Rust Playground The relevant code is:
{let mut container = &mut top_level;
loop {
let (packet, ppo, relative_position2) = pp.next()?;
depth += relative_position;
// Find the right container.
if relative_position == 0 {
// The old packet and the new packet are siblings; container
// is still correct.
} else {
// Start from the root...
let traversal_depth
= depth - if relative_position > 0 { 1 } else { 0 };
container = &mut top_level;
if traversal_depth > 0 {
for _ in 1..traversal_depth + 1 {
...
}
}
container.packets.push(packet);
...
}}
Any ideas on how I can implement this simple cache to avoid the "cannot borrow top_level
as mutable more than once at a time"?
Thanks!