Skip to main content

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}