mpi/attribute.rs
1//! Attribute caching on communicators. Mirrors rsmpi's `attribute` module: a
2//! keyval identifies a slot, and arbitrary typed values can be cached on a
3//! communicator and retrieved later.
4//!
5//! ```
6//! use mpi::attribute::{create_keyval, CommunicatorAttributes};
7//! # fn demo(world: &impl mpi::topology::Communicator) {
8//! let key = create_keyval();
9//! world.set_attr(&key, 123u64);
10//! assert_eq!(world.get_attr::<u64>(&key), Some(123));
11//! # }
12//! ```
13
14use std::any::Any;
15use std::sync::atomic::{AtomicI32, Ordering};
16
17use crate::topology::Communicator;
18
19/// A key identifying an attribute slot (`MPI_Comm_create_keyval`).
20#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
21pub struct CommKeyval {
22 id: i32,
23}
24
25impl CommKeyval {
26 /// The raw keyval id.
27 pub fn id(&self) -> i32 {
28 self.id
29 }
30}
31
32static NEXT_KEYVAL: AtomicI32 = AtomicI32::new(1);
33
34/// Create a fresh communicator keyval (`MPI_Comm_create_keyval`).
35pub fn create_keyval() -> CommKeyval {
36 CommKeyval {
37 id: NEXT_KEYVAL.fetch_add(1, Ordering::Relaxed),
38 }
39}
40
41/// Attribute-caching operations on communicators. Blanket-implemented for every
42/// [`Communicator`].
43pub trait CommunicatorAttributes: Communicator {
44 /// Cache `value` under `key` on this communicator (`MPI_Comm_set_attr`).
45 fn set_attr<T: Any + Send + Sync>(&self, key: &CommKeyval, value: T) {
46 self.comm_data()
47 .attributes
48 .lock()
49 .unwrap()
50 .insert(key.id, Box::new(value));
51 }
52
53 /// Retrieve a clone of the attribute cached under `key`
54 /// (`MPI_Comm_get_attr`), if present and of type `T`.
55 fn get_attr<T: Any + Clone>(&self, key: &CommKeyval) -> Option<T> {
56 self.comm_data()
57 .attributes
58 .lock()
59 .unwrap()
60 .get(&key.id)
61 .and_then(|b| b.downcast_ref::<T>())
62 .cloned()
63 }
64
65 /// Whether an attribute is cached under `key`.
66 fn has_attr(&self, key: &CommKeyval) -> bool {
67 self.comm_data()
68 .attributes
69 .lock()
70 .unwrap()
71 .contains_key(&key.id)
72 }
73
74 /// Remove the attribute cached under `key` (`MPI_Comm_delete_attr`).
75 fn delete_attr(&self, key: &CommKeyval) {
76 self.comm_data().attributes.lock().unwrap().remove(&key.id);
77 }
78}
79
80impl<C: Communicator + ?Sized> CommunicatorAttributes for C {}
81
82/// Re-exports for `use mpi::attribute::traits::*;`.
83pub mod traits {
84 pub use super::CommunicatorAttributes;
85}