I wanted something like this:
struct Node {
outbound_mailboxes: Vec<u32>, // memory used for inter-node comms
inbound_links: Vec<(usize, usize)>, // (source node index, source node outbound mailbox index)
}
fn node_action(inputs: Vec<&u32>, outputs: Vec<&mut u32>) { // keeping this signature is important
println!("{:?}, {:?}", inputs, outputs);
// more code: think about the inputs; write to the outputs
}
fn main() {
// 3 nodes bidirectionally connected 0--1 and 0--2
let mut nodes = vec![
Node { outbound_mailboxes: vec![0, 1], inbound_links: vec![(1, 0), (2, 0)] },
Node { outbound_mailboxes: vec![2], inbound_links: vec![(0, 0)] },
Node { outbound_mailboxes: vec![3], inbound_links: vec![(0, 1)] },
];
// trigger node 0 action
let mut inputs: Vec<&u32> = Vec::new();
for (i, j) in &nodes[0].inbound_links {
inputs.push(&nodes[*i].outbound_mailboxes[*j]);
}
let outputs: Vec<&mut u32> = nodes[0].outbound_mailboxes.iter_mut().map(|m| m).collect();
node_action(inputs, outputs);
}
It did not work:
error[E0502]: cannot borrow `nodes` as mutable because it is also borrowed as immutable
--> src/main.rs:24:34
|
22 | inputs.push(&nodes[*i].outbound_mailboxes[*j]);
| ----- immutable borrow occurs here
23 | }
24 | let outputs: Vec<&mut u32> = nodes[0].outbound_mailboxes.iter_mut().map(|m| m).collect();
| ^^^^^ mutable borrow occurs here
25 | node_action(inputs, outputs);
| ------ immutable borrow later used here
Shepmaster suggested that How to get mutable references to two array elements at the same time? already answered my question. With Shepmaster's additional comments I now understand why (it was not clear to me researching that answer prior to posting).
Thank you very much Shepmaster -- your patience is greatly appreciated; apologies for not understanding more quickly.
Refactored code that looks to fully meet my needs:
struct Node {
outbound_mailboxes: Vec<u32>, // memory used for inter-node comms
inbound_links: Vec<(usize, usize)>, // (source node index, source node outbound mailbox index)
}
fn node_action(inputs: &[&u32], outputs: &[&mut u32]) {
println!("{:?}, {:?}", inputs, outputs)
}
fn trigger_action(nodes: &mut [Node], target_node_idx: usize) {
assert!(target_node_idx < nodes.len());
let (left_nodes, rest) = nodes.split_at_mut(target_node_idx);
let (target_node, right_nodes) = rest.split_first_mut().unwrap();
let outputs: Vec<&mut u32> = target_node.outbound_mailboxes.iter_mut().collect();
let mut inputs: Vec<&u32> = Vec::new();
for (i, j) in &target_node.inbound_links {
assert_ne!(*i, target_node_idx);
let node = {
if *i < target_node_idx { &left_nodes[*i] }
else { &right_nodes[*i - (target_node_idx + 1)] }
};
inputs.push(&node.outbound_mailboxes[*j]);
}
node_action(&inputs, &outputs)
}
fn main() {
// 3 nodes bidirectionally connected 0--1 and 0--2
let mut nodes = vec![
Node { outbound_mailboxes: vec![0, 1], inbound_links: vec![(1, 0), (2, 0)] },
Node { outbound_mailboxes: vec![2], inbound_links: vec![(0, 0)] },
Node { outbound_mailboxes: vec![3], inbound_links: vec![(0, 1)] },
];
trigger_action(&mut nodes, 0); // prints "[2, 3], [0, 1]"
trigger_action(&mut nodes, 1); // prints "[0], [2]"
trigger_action(&mut nodes, 2); // prints "[0], [1]"
}