relrc 0.5.0

Reference counted pointers, with relationships to other pointers.
Documentation
use std::collections::BTreeSet;

use mpi::traits::Communicator;
use relrc::{
    mpi::{MPIMode, RelRcCommunicator},
    RelRc,
};

fn count_ancestors(relrc: &RelRc<usize, usize>) -> usize {
    relrc.detach(&BTreeSet::new()).n_ancestors()
}

fn main() {
    let universe = mpi::initialize().unwrap();
    let world = universe.world();
    let size = world.size();
    let rank = world.rank();

    if size != 2 {
        panic!("Size of MPI_COMM_WORLD must be 2, but is {}!", size);
    }

    // The first process has a set of 4 RelRc objects, the second has 2 of them.
    let mut all_relrcs = match rank {
        0 => {
            // Create the first set of RelRc objects forming a diamond pattern
            let root1 = RelRc::new(0);
            let left_child1 = RelRc::with_parents(1, vec![(root1.clone(), 1)]);
            let right_child1 = RelRc::with_parents(2, vec![(root1.clone(), 2)]);
            let grandchild1 = RelRc::with_parents(
                3,
                vec![(left_child1.clone(), 11), (right_child1.clone(), 12)],
            );

            vec![root1, left_child1, right_child1, grandchild1]
        }
        1 => {
            // Create the second set of RelRc objects
            let root2 = RelRc::new(0);
            let left_child2 = RelRc::with_parents(1, vec![(root2.clone(), 1)]);

            vec![root2, left_child2]
        }
        _ => unreachable!(),
    };

    println!(
        "[begin] rank {rank}: total number of objects: {}",
        count_ancestors(all_relrcs.last().unwrap())
    );

    // Sending the grandchild of process 0 to process 1 should create 2 new
    // RelRc objects in process 1.
    match rank {
        0 => {
            world
                .process_at_rank(1)
                .send_relrc(&all_relrcs[3], MPIMode::default());
            println!("rank {rank}: sent grandchild");
        }
        1 => {
            let left_child2 = all_relrcs[1].clone();
            let received = world
                .process_at_rank(0)
                .recv_relrc(all_relrcs.clone(), MPIMode::default());
            println!("rank {rank}: received grandchild");

            assert_eq!(count_ancestors(&received), 4);
            assert_eq!(received.all_parents().len(), 2);
            assert!(received
                .all_parents()
                .any(|c| RelRc::ptr_eq(c, &left_child2)));

            all_relrcs.push(received);
        }
        _ => unreachable!(),
    }

    println!(
        "[end] rank {rank}: total number of objects: {}",
        count_ancestors(all_relrcs.last().unwrap())
    );

    println!("done at rank {}", rank);
}