mpi/
datatype.rs

1//! The core function of MPI is getting data from point A to point B (where A and B are e.g. single
2//! processes, multiple processes, the filesystem, ...). It offers facilities to describe that data
3//! (layout in memory, behavior under certain operators) that go beyound a start address and a
4//! number of bytes.
5//!
6//! An MPI datatype describes a memory layout and semantics (e.g. in a collective reduce
7//! operation). There are several pre-defined `SystemDatatype`s which directly correspond to Rust
8//! primitive types, such as `MPI_DOUBLE` and `f64`. A direct relationship between a Rust type and
9//! an MPI datatype is covered by the `Equivalence` trait. Starting from the
10//! `SystemDatatype`s, the user can build various `UserDatatype`s, e.g. to describe the layout of a
11//! struct (which should then implement `Equivalence`) or to intrusively describe parts of
12//! an object in memory like all elements below the diagonal of a dense matrix stored in row-major
13//! order.
14//!
15//! ## Derived Datatypes
16//! Derived MPI datatypes can exist in either an "uncommitted" or "committed" state. Only
17//! "committed" datatypes can be used in MPI communication. There is a cost to committing a
18//! datatype: only a final aggregate type should be committed when building it from component
19//! derived datatypes.
20//!
21//! In order to represent the difference between committed and uncommitted `MPI_Datatype` objects,
22//! two different flavors of types representing the "committed"-ness of the type are exposed.
23//! Orthogonally, there are types representing both "owned" `MPI_Datatype` objects and "borrowed"
24//! `MPI_Datatype` objects. This means there are four different types for `MPI_Datatype`:
25//! - `UserDatatype` represents a committed, owned `MPI_Datatype`
26//! - `DatatypeRef<'_>` represents a committed, borrowed `MPI_Datatype`.
27//!   - All builtin types are `DatatypeRef<'static>`
28//! - `UncommittedUserDatatype` represents an uncommitted, owned `MPI_Datatype`
29//! - `UncommittedDatatypeRef<'_>` represents an uncommitted, borrowed `MPI_Datatype`
30//!
31//! Along with this, there are two traits that are applied to these types:
32//! - `UncommittedDatatype` indicates the type represents a possibly uncommitted `MPI_Datatype`
33//! - `Datatype` indicates the type represents a committed `MPI_Datatype`
34//!
35//! An important concept here is that all committed `Datatype` objects are also
36//! `UncommittedDatatype` objects. This may seem unintuitive at first, but as far as MPI is
37//! concerned, "committing" a datatype is purely a promotion, enabling more capabilities. This
38//! allows `Datatype` and `UncommittedDatatype` objects to be used interchangeably in the same
39//! `Datatype` constructors.
40//!
41//! For more information on derived datatypes, see section 4.1 of the MPI 3.1 Standard.
42//!
43//! ## Data Buffers
44//! A `Buffer` describes a specific piece of data in memory that MPI should operate on. In addition
45//! to specifying the datatype of the data. It knows the address in memory where the data begins
46//! and how many instances of the datatype are contained in the data. The `Buffer` trait is
47//! implemented for slices that contain types implementing `Equivalence`.
48//!
49//! In order to use arbitrary datatypes to describe the contents of a slice, the `View` type is
50//! provided. However, since it can be used to instruct the underlying MPI implementation to
51//! rummage around arbitrary parts of memory, its constructors are currently marked unsafe.
52//!
53//! # Unfinished features
54//!
55//! - **4.1.3**: Subarray datatype constructors, `MPI_Type_create_subarray()`,
56//! - **4.1.4**: Distributed array datatype constructors, `MPI_Type_create_darray()`
57//! - **4.1.5**: Address and size functions, `MPI_Get_address()`, `MPI_Aint_add()`,
58//! `MPI_Aint_diff()`, `MPI_Type_size()`, `MPI_Type_size_x()`
59//! - **4.1.7**: Extent and bounds of datatypes: `MPI_Type_get_extent()`,
60//! `MPI_Type_get_extent_x()`, `MPI_Type_create_resized()`
61//! - **4.1.8**: True extent of datatypes, `MPI_Type_get_true_extent()`,
62//! `MPI_Type_get_true_extent_x()`
63//! - **4.1.11**: `MPI_Get_elements()`, `MPI_Get_elements_x()`
64//! - **4.1.13**: Decoding a datatype, `MPI_Type_get_envelope()`, `MPI_Type_get_contents()`
65//! - **4.3**: Canonical pack and unpack, `MPI_Pack_external()`, `MPI_Unpack_external()`,
66//! `MPI_Pack_external_size()`
67
68use std::borrow::Borrow;
69use std::marker::PhantomData;
70use std::os::raw::c_void;
71use std::{mem, slice};
72
73use conv::ConvUtil;
74
75use super::{Address, Count};
76
77use crate::ffi;
78use crate::ffi::MPI_Datatype;
79
80use crate::raw::traits::*;
81
82use crate::with_uninitialized;
83
84/// Datatype traits
85pub mod traits {
86    pub use super::{
87        AsDatatype, Buffer, BufferMut, Collection, Datatype, Equivalence, Partitioned,
88        PartitionedBuffer, PartitionedBufferMut, Pointer, PointerMut, UncommittedDatatype,
89    };
90}
91
92/// A reference to an MPI data type.
93///
94/// This is similar to a raw `MPI_Datatype` but is guaranteed to be a valid for `'a`.
95#[derive(Copy, Clone, Debug)]
96pub struct DatatypeRef<'a> {
97    datatype: MPI_Datatype,
98    phantom: PhantomData<&'a ()>,
99}
100
101unsafe impl<'a> AsRaw for DatatypeRef<'a> {
102    type Raw = MPI_Datatype;
103    fn as_raw(&self) -> Self::Raw {
104        self.datatype
105    }
106}
107
108impl<'a> FromRaw for DatatypeRef<'a> {
109    unsafe fn from_raw(datatype: MPI_Datatype) -> Self {
110        Self {
111            datatype,
112            phantom: PhantomData,
113        }
114    }
115}
116
117unsafe impl<'a> MatchesRaw for DatatypeRef<'a> {}
118
119impl<'a> Datatype for DatatypeRef<'a> {}
120impl<'a> UncommittedDatatype for DatatypeRef<'a> {
121    type DuplicatedDatatype = UserDatatype;
122}
123
124impl<'a> From<DatatypeRef<'a>> for UncommittedDatatypeRef<'a> {
125    fn from(datatype_ref: DatatypeRef<'a>) -> Self {
126        unsafe { UncommittedDatatypeRef::from_raw(datatype_ref.as_raw()) }
127    }
128}
129
130/// A reference to an uncommitted, or potentially uncommitted, MPI data type.
131///
132/// This is similar to a raw uncommitted `MPI_Datatype` but is guaranteed to be a valid for `'a`.
133#[derive(Copy, Clone, Debug)]
134pub struct UncommittedDatatypeRef<'a> {
135    datatype: MPI_Datatype,
136    phantom: PhantomData<&'a ()>,
137}
138
139unsafe impl<'a> AsRaw for UncommittedDatatypeRef<'a> {
140    type Raw = MPI_Datatype;
141    fn as_raw(&self) -> Self::Raw {
142        self.datatype
143    }
144}
145
146impl<'a> FromRaw for UncommittedDatatypeRef<'a> {
147    unsafe fn from_raw(datatype: MPI_Datatype) -> Self {
148        Self {
149            datatype,
150            phantom: PhantomData,
151        }
152    }
153}
154
155unsafe impl<'a> MatchesRaw for UncommittedDatatypeRef<'a> {}
156
157impl<'a> UncommittedDatatype for UncommittedDatatypeRef<'a> {
158    type DuplicatedDatatype = UncommittedUserDatatype;
159}
160
161/// A system datatype, e.g. `MPI_FLOAT`
162///
163/// # Standard section(s)
164///
165/// 3.2.2
166pub type SystemDatatype = DatatypeRef<'static>;
167
168/// A direct equivalence exists between the implementing type and an MPI datatype
169///
170/// # Standard section(s)
171///
172/// 3.2.2
173pub unsafe trait Equivalence {
174    /// The type of the equivalent MPI datatype (e.g. `SystemDatatype` or `UserDatatype`)
175    type Out: Datatype;
176    /// The MPI datatype that is equivalent to this Rust type
177    fn equivalent_datatype() -> Self::Out;
178}
179
180macro_rules! equivalent_system_datatype {
181    ($rstype:path, $mpitype:path) => {
182        unsafe impl Equivalence for $rstype {
183            type Out = SystemDatatype;
184            fn equivalent_datatype() -> Self::Out {
185                unsafe { DatatypeRef::from_raw($mpitype) }
186            }
187        }
188    };
189}
190
191equivalent_system_datatype!(bool, ffi::RSMPI_C_BOOL);
192
193equivalent_system_datatype!(f32, ffi::RSMPI_FLOAT);
194equivalent_system_datatype!(f64, ffi::RSMPI_DOUBLE);
195
196equivalent_system_datatype!(i8, ffi::RSMPI_INT8_T);
197equivalent_system_datatype!(i16, ffi::RSMPI_INT16_T);
198equivalent_system_datatype!(i32, ffi::RSMPI_INT32_T);
199equivalent_system_datatype!(i64, ffi::RSMPI_INT64_T);
200
201equivalent_system_datatype!(u8, ffi::RSMPI_UINT8_T);
202equivalent_system_datatype!(u16, ffi::RSMPI_UINT16_T);
203equivalent_system_datatype!(u32, ffi::RSMPI_UINT32_T);
204equivalent_system_datatype!(u64, ffi::RSMPI_UINT64_T);
205
206#[cfg(target_pointer_width = "32")]
207equivalent_system_datatype!(usize, ffi::RSMPI_UINT32_T);
208#[cfg(target_pointer_width = "32")]
209equivalent_system_datatype!(isize, ffi::RSMPI_INT32_T);
210
211#[cfg(target_pointer_width = "64")]
212equivalent_system_datatype!(usize, ffi::RSMPI_UINT64_T);
213#[cfg(target_pointer_width = "64")]
214equivalent_system_datatype!(isize, ffi::RSMPI_INT64_T);
215
216#[cfg(feature = "complex")]
217/// Implement direct equivalence for complex types
218pub mod complex_datatype {
219    use super::{ffi, DatatypeRef, Equivalence, FromRaw, SystemDatatype};
220    use num_complex::{Complex32, Complex64};
221    equivalent_system_datatype!(Complex32, ffi::RSMPI_FLOAT_COMPLEX);
222    equivalent_system_datatype!(Complex64, ffi::RSMPI_DOUBLE_COMPLEX);
223}
224
225/// A user defined MPI datatype
226///
227/// # Standard section(s)
228///
229/// 4
230pub struct UserDatatype(MPI_Datatype);
231
232impl UserDatatype {
233    /// Constructs a new datatype by concatenating `count` repetitions of `oldtype`
234    ///
235    /// # Examples
236    /// See `examples/contiguous.rs`
237    ///
238    /// # Standard section(s)
239    ///
240    /// 4.1.2
241    pub fn contiguous<D>(count: Count, oldtype: &D) -> UserDatatype
242    where
243        D: UncommittedDatatype,
244    {
245        UncommittedUserDatatype::contiguous(count, oldtype).commit()
246    }
247
248    /// Construct a new datatype out of `count` blocks of `blocklength` elements of `oldtype`
249    /// concatenated with the start of consecutive blocks placed `stride` elements apart.
250    ///
251    /// # Examples
252    /// See `examples/vector.rs`
253    ///
254    /// # Standard section(s)
255    ///
256    /// 4.1.2
257    pub fn vector<D>(count: Count, blocklength: Count, stride: Count, oldtype: &D) -> UserDatatype
258    where
259        D: UncommittedDatatype,
260    {
261        UncommittedUserDatatype::vector(count, blocklength, stride, oldtype).commit()
262    }
263
264    /// Like `vector()` but `stride` is given in bytes rather than elements of `oldtype`.
265    ///
266    /// # Standard section(s)
267    ///
268    /// 4.1.2
269    pub fn heterogeneous_vector<D>(
270        count: Count,
271        blocklength: Count,
272        stride: Address,
273        oldtype: &D,
274    ) -> UserDatatype
275    where
276        D: UncommittedDatatype,
277    {
278        UncommittedUserDatatype::heterogeneous_vector(count, blocklength, stride, oldtype).commit()
279    }
280
281    /// Constructs a new type out of multiple blocks of individual length and displacement.
282    /// Block `i` will be `blocklengths[i]` items of datytpe `oldtype` long and displaced by
283    /// `dispplacements[i]` items of the `oldtype`.
284    ///
285    /// # Standard section(s)
286    ///
287    /// 4.1.2
288    pub fn indexed<D>(blocklengths: &[Count], displacements: &[Count], oldtype: &D) -> UserDatatype
289    where
290        D: UncommittedDatatype,
291    {
292        UncommittedUserDatatype::indexed(blocklengths, displacements, oldtype).commit()
293    }
294
295    /// Constructs a new type out of multiple blocks of individual length and displacement.
296    /// Block `i` will be `blocklengths[i]` items of datytpe `oldtype` long and displaced by
297    /// `dispplacements[i]` bytes.
298    ///
299    /// # Standard section(s)
300    ///
301    /// 4.1.2
302    pub fn heterogeneous_indexed<D>(
303        blocklengths: &[Count],
304        displacements: &[Address],
305        oldtype: &D,
306    ) -> UserDatatype
307    where
308        D: UncommittedDatatype,
309    {
310        UncommittedUserDatatype::heterogeneous_indexed(blocklengths, displacements, oldtype)
311            .commit()
312    }
313
314    /// Construct a new type out of blocks of the same length and individual displacements.
315    ///
316    /// # Standard section(s)
317    ///
318    /// 4.1.2
319    pub fn indexed_block<D>(
320        blocklength: Count,
321        displacements: &[Count],
322        oldtype: &D,
323    ) -> UserDatatype
324    where
325        D: UncommittedDatatype,
326    {
327        UncommittedUserDatatype::indexed_block(blocklength, displacements, oldtype).commit()
328    }
329
330    /// Construct a new type out of blocks of the same length and individual displacements.
331    /// Displacements are in bytes.
332    ///
333    /// # Standard section(s)
334    ///
335    /// 4.1.2
336    pub fn heterogeneous_indexed_block<D>(
337        blocklength: Count,
338        displacements: &[Address],
339        oldtype: &D,
340    ) -> UserDatatype
341    where
342        D: UncommittedDatatype,
343    {
344        UncommittedUserDatatype::heterogeneous_indexed_block(blocklength, displacements, oldtype)
345            .commit()
346    }
347
348    /// Constructs a new datatype out of blocks of different length, displacement and datatypes
349    ///
350    /// # Examples
351    /// See `examples/structured.rs`
352    ///
353    /// # Standard section(s)
354    ///
355    /// 4.1.2
356    pub fn structured<D>(
357        blocklengths: &[Count],
358        displacements: &[Address],
359        types: &[D],
360    ) -> UserDatatype
361    where
362        D: UncommittedDatatype + MatchesRaw<Raw = MPI_Datatype>,
363    {
364        UncommittedUserDatatype::structured(blocklengths, displacements, types).commit()
365    }
366
367    /// Creates a DatatypeRef from this datatype object.
368    pub fn as_ref(&self) -> DatatypeRef<'_> {
369        unsafe { DatatypeRef::from_raw(self.as_raw()) }
370    }
371}
372
373// TODO and NOTE: These impls are not 100% implemented, but reflect the larger reality that the
374// current API does not strongly enforce the threading requirements of MPI's `MPI_Init_thread`
375// function. In order to enforce uniformity across platforms, these traits are explicitly applied.
376// Due to the nature of MPI implementations, without this declaration some implementations of
377// MPI would otherwise be Send + Sync by default, and others would be !Sync by default.
378unsafe impl Send for UserDatatype {}
379unsafe impl Sync for UserDatatype {}
380
381impl Clone for UserDatatype {
382    fn clone(&self) -> Self {
383        self.dup()
384    }
385}
386
387impl Drop for UserDatatype {
388    fn drop(&mut self) {
389        unsafe {
390            ffi::MPI_Type_free(&mut self.0);
391        }
392        assert_eq!(self.0, unsafe { ffi::RSMPI_DATATYPE_NULL });
393    }
394}
395
396unsafe impl AsRaw for UserDatatype {
397    type Raw = MPI_Datatype;
398    fn as_raw(&self) -> Self::Raw {
399        self.0
400    }
401}
402
403impl FromRaw for UserDatatype {
404    unsafe fn from_raw(handle: MPI_Datatype) -> Self {
405        assert_ne!(handle, ffi::RSMPI_DATATYPE_NULL);
406        UserDatatype(handle)
407    }
408}
409
410unsafe impl MatchesRaw for UserDatatype {}
411
412impl Datatype for UserDatatype {}
413impl UncommittedDatatype for UserDatatype {
414    type DuplicatedDatatype = UserDatatype;
415}
416
417impl<'a> From<&'a UserDatatype> for DatatypeRef<'a> {
418    fn from(datatype: &'a UserDatatype) -> Self {
419        unsafe { DatatypeRef::from_raw(datatype.as_raw()) }
420    }
421}
422
423impl<'a> From<&'a UserDatatype> for UncommittedDatatypeRef<'a> {
424    fn from(datatype: &'a UserDatatype) -> Self {
425        unsafe { UncommittedDatatypeRef::from_raw(datatype.as_raw()) }
426    }
427}
428
429/// Represents an MPI datatype that has not yet been committed. Can be used to build up more complex
430/// datatypes before committing.
431///
432/// UncommittedUserDatatype does not implement Datatype - it cannot be used as a datatype, and must be
433/// commited to retrieve a UserDatatype that implements Datatype.
434///
435/// # Standard section(s)
436/// 4.1.9
437pub struct UncommittedUserDatatype(MPI_Datatype);
438
439impl UncommittedUserDatatype {
440    /// Constructs a new datatype by concatenating `count` repetitions of `oldtype`
441    ///
442    /// # Examples
443    /// See `examples/contiguous.rs`
444    ///
445    /// # Standard section(s)
446    ///
447    /// 4.1.2
448    pub fn contiguous<D>(count: Count, oldtype: &D) -> Self
449    where
450        D: UncommittedDatatype,
451    {
452        unsafe {
453            UncommittedUserDatatype(
454                with_uninitialized(|newtype| {
455                    ffi::MPI_Type_contiguous(count, oldtype.as_raw(), newtype)
456                })
457                .1,
458            )
459        }
460    }
461
462    /// Construct a new datatype out of `count` blocks of `blocklength` elements of `oldtype`
463    /// concatenated with the start of consecutive blocks placed `stride` elements apart.
464    ///
465    /// # Examples
466    /// See `examples/vector.rs`
467    ///
468    /// # Standard section(s)
469    ///
470    /// 4.1.2
471    pub fn vector<D>(count: Count, blocklength: Count, stride: Count, oldtype: &D) -> Self
472    where
473        D: UncommittedDatatype,
474    {
475        unsafe {
476            UncommittedUserDatatype(
477                with_uninitialized(|newtype| {
478                    ffi::MPI_Type_vector(count, blocklength, stride, oldtype.as_raw(), newtype)
479                })
480                .1,
481            )
482        }
483    }
484
485    /// Like `vector()` but `stride` is given in bytes rather than elements of `oldtype`.
486    ///
487    /// # Standard section(s)
488    ///
489    /// 4.1.2
490    pub fn heterogeneous_vector<D>(
491        count: Count,
492        blocklength: Count,
493        stride: Address,
494        oldtype: &D,
495    ) -> Self
496    where
497        D: UncommittedDatatype,
498    {
499        unsafe {
500            UncommittedUserDatatype(
501                with_uninitialized(|newtype| {
502                    ffi::MPI_Type_create_hvector(
503                        count,
504                        blocklength,
505                        stride,
506                        oldtype.as_raw(),
507                        newtype,
508                    )
509                })
510                .1,
511            )
512        }
513    }
514
515    /// Constructs a new type out of multiple blocks of individual length and displacement.
516    /// Block `i` will be `blocklengths[i]` items of datytpe `oldtype` long and displaced by
517    /// `dispplacements[i]` items of the `oldtype`.
518    ///
519    /// # Standard section(s)
520    ///
521    /// 4.1.2
522    pub fn indexed<D>(blocklengths: &[Count], displacements: &[Count], oldtype: &D) -> Self
523    where
524        D: UncommittedDatatype,
525    {
526        assert_eq!(
527            blocklengths.len(),
528            displacements.len(),
529            "'blocklengths' and 'displacements' must be the same length"
530        );
531
532        unsafe {
533            UncommittedUserDatatype(
534                with_uninitialized(|newtype| {
535                    ffi::MPI_Type_indexed(
536                        blocklengths.count(),
537                        blocklengths.as_ptr(),
538                        displacements.as_ptr(),
539                        oldtype.as_raw(),
540                        newtype,
541                    )
542                })
543                .1,
544            )
545        }
546    }
547
548    /// Constructs a new type out of multiple blocks of individual length and displacement.
549    /// Block `i` will be `blocklengths[i]` items of datytpe `oldtype` long and displaced by
550    /// `dispplacements[i]` bytes.
551    ///
552    /// # Standard section(s)
553    ///
554    /// 4.1.2
555    pub fn heterogeneous_indexed<D>(
556        blocklengths: &[Count],
557        displacements: &[Address],
558        oldtype: &D,
559    ) -> Self
560    where
561        D: UncommittedDatatype,
562    {
563        assert_eq!(
564            blocklengths.len(),
565            displacements.len(),
566            "'blocklengths' and 'displacements' must be the same length"
567        );
568        unsafe {
569            UncommittedUserDatatype(
570                with_uninitialized(|newtype| {
571                    ffi::MPI_Type_create_hindexed(
572                        blocklengths.count(),
573                        blocklengths.as_ptr(),
574                        displacements.as_ptr(),
575                        oldtype.as_raw(),
576                        newtype,
577                    )
578                })
579                .1,
580            )
581        }
582    }
583
584    /// Construct a new type out of blocks of the same length and individual displacements.
585    ///
586    /// # Standard section(s)
587    ///
588    /// 4.1.2
589    pub fn indexed_block<D>(blocklength: Count, displacements: &[Count], oldtype: &D) -> Self
590    where
591        D: UncommittedDatatype,
592    {
593        unsafe {
594            UncommittedUserDatatype(
595                with_uninitialized(|newtype| {
596                    ffi::MPI_Type_create_indexed_block(
597                        displacements.count(),
598                        blocklength,
599                        displacements.as_ptr(),
600                        oldtype.as_raw(),
601                        newtype,
602                    )
603                })
604                .1,
605            )
606        }
607    }
608
609    /// Construct a new type out of blocks of the same length and individual displacements.
610    /// Displacements are in bytes.
611    ///
612    /// # Standard section(s)
613    ///
614    /// 4.1.2
615    pub fn heterogeneous_indexed_block<D>(
616        blocklength: Count,
617        displacements: &[Address],
618        oldtype: &D,
619    ) -> Self
620    where
621        D: UncommittedDatatype,
622    {
623        unsafe {
624            UncommittedUserDatatype(
625                with_uninitialized(|newtype| {
626                    ffi::MPI_Type_create_hindexed_block(
627                        displacements.count(),
628                        blocklength,
629                        displacements.as_ptr(),
630                        oldtype.as_raw(),
631                        newtype,
632                    )
633                })
634                .1,
635            )
636        }
637    }
638
639    /// Constructs a new datatype out of blocks of different length, displacement and datatypes
640    ///
641    /// # Examples
642    /// See `examples/structured.rs`
643    ///
644    /// # Standard section(s)
645    ///
646    /// 4.1.2
647    pub fn structured<D>(blocklengths: &[Count], displacements: &[Address], types: &[D]) -> Self
648    where
649        D: UncommittedDatatype + MatchesRaw<Raw = MPI_Datatype>,
650    {
651        assert_eq!(
652            blocklengths.len(),
653            displacements.len(),
654            "'displacements', 'blocklengths', and 'types' must be the same length"
655        );
656        assert_eq!(
657            blocklengths.len(),
658            types.len(),
659            "'displacements', 'blocklengths', and 'types' must be the same length"
660        );
661
662        unsafe {
663            UncommittedUserDatatype(
664                with_uninitialized(|newtype| {
665                    ffi::MPI_Type_create_struct(
666                        blocklengths.count(),
667                        blocklengths.as_ptr(),
668                        displacements.as_ptr(),
669                        types.as_ptr() as *const _,
670                        newtype,
671                    )
672                })
673                .1,
674            )
675        }
676    }
677
678    /// Commits a datatype to a specific representation so that it can be used in MPI calls.
679    ///
680    /// # Standard section(s)
681    /// 4.1.9
682    pub fn commit(mut self) -> UserDatatype {
683        let handle = self.0;
684        unsafe {
685            ffi::MPI_Type_commit(&mut self.0);
686        }
687        mem::forget(self);
688        UserDatatype(handle)
689    }
690
691    /// Creates an UncommittedDatatypeRef from this datatype object.
692    pub fn as_ref(&self) -> UncommittedDatatypeRef<'_> {
693        unsafe { UncommittedDatatypeRef::from_raw(self.as_raw()) }
694    }
695}
696
697impl Clone for UncommittedUserDatatype {
698    fn clone(&self) -> Self {
699        self.dup()
700    }
701}
702
703impl Drop for UncommittedUserDatatype {
704    fn drop(&mut self) {
705        unsafe {
706            ffi::MPI_Type_free(&mut self.0);
707        }
708        assert_eq!(self.0, unsafe { ffi::RSMPI_DATATYPE_NULL });
709    }
710}
711
712unsafe impl AsRaw for UncommittedUserDatatype {
713    type Raw = MPI_Datatype;
714    fn as_raw(&self) -> Self::Raw {
715        self.0
716    }
717}
718
719impl FromRaw for UncommittedUserDatatype {
720    unsafe fn from_raw(handle: MPI_Datatype) -> Self {
721        assert_ne!(handle, ffi::RSMPI_DATATYPE_NULL);
722        UncommittedUserDatatype(handle)
723    }
724}
725
726unsafe impl MatchesRaw for UncommittedUserDatatype {}
727
728impl UncommittedDatatype for UncommittedUserDatatype {
729    type DuplicatedDatatype = UncommittedUserDatatype;
730}
731
732impl<'a> From<&'a UncommittedUserDatatype> for UncommittedDatatypeRef<'a> {
733    fn from(datatype: &'a UncommittedUserDatatype) -> Self {
734        unsafe { UncommittedDatatypeRef::from_raw(datatype.as_raw()) }
735    }
736}
737
738/// A Datatype describes the layout of messages in memory.
739///
740/// `Datatype` always represents a committed datatype that can be immediately used for sending and
741/// receiving messages. `UncommittedDatatype` is used for datatypes that are possibly uncommitted.
742pub trait Datatype: UncommittedDatatype {}
743impl<'a, D> Datatype for &'a D where D: 'a + Datatype {}
744
745/// An UncommittedDatatype is a partial description of the layout of messages in memory which may
746/// not yet have been committed to an implementation-defined message format.
747///
748/// Committed datatypes can be treated as-if they are uncommitted.
749pub trait UncommittedDatatype: AsRaw<Raw = MPI_Datatype> {
750    /// The type returned when the datatype is duplicated.
751    type DuplicatedDatatype: FromRaw<Raw = MPI_Datatype>;
752
753    /// Creates a new datatype with the same key-values as this datatype.
754    ///
755    /// # Standard section(s)
756    /// 4.1.10
757    fn dup(&self) -> Self::DuplicatedDatatype {
758        unsafe {
759            Self::DuplicatedDatatype::from_raw(
760                with_uninitialized(|newtype| ffi::MPI_Type_dup(self.as_raw(), newtype)).1,
761            )
762        }
763    }
764}
765impl<'a, D> UncommittedDatatype for &'a D
766where
767    D: 'a + UncommittedDatatype,
768{
769    type DuplicatedDatatype = <D as UncommittedDatatype>::DuplicatedDatatype;
770}
771
772/// Something that has an associated datatype
773pub unsafe trait AsDatatype {
774    /// The type of the associated MPI datatype (e.g. `SystemDatatype` or `UserDatatype`)
775    type Out: Datatype;
776    /// The associated MPI datatype
777    fn as_datatype(&self) -> Self::Out;
778}
779
780unsafe impl<T> AsDatatype for T
781where
782    T: Equivalence,
783{
784    type Out = <T as Equivalence>::Out;
785    fn as_datatype(&self) -> Self::Out {
786        <T as Equivalence>::equivalent_datatype()
787    }
788}
789
790unsafe impl<T> AsDatatype for [T]
791where
792    T: Equivalence,
793{
794    type Out = <T as Equivalence>::Out;
795    fn as_datatype(&self) -> Self::Out {
796        <T as Equivalence>::equivalent_datatype()
797    }
798}
799
800unsafe impl<T> AsDatatype for Vec<T>
801where
802    T: Equivalence,
803{
804    type Out = <T as Equivalence>::Out;
805    fn as_datatype(&self) -> Self::Out {
806        <T as Equivalence>::equivalent_datatype()
807    }
808}
809
810unsafe impl<T, const D: usize> AsDatatype for [T; D]
811where
812    T: Equivalence,
813{
814    type Out = <T as Equivalence>::Out;
815    fn as_datatype(&self) -> Self::Out {
816        <T as Equivalence>::equivalent_datatype()
817    }
818}
819
820#[doc(hidden)]
821pub mod internal {
822    #[cfg(feature = "derive")]
823    pub fn check_derive_equivalence_universe_state(type_name: &str) {
824        use crate::environment::UNIVERSE_STATE;
825
826        // Take lock on UNIVERSE_STATE to prevent racing with mpi::init and mpi::finalize.
827        let universe_state = UNIVERSE_STATE.read().unwrap();
828
829        if !crate::environment::is_initialized() {
830            panic!(
831                "\n\
832                 RSMPI PANIC: Pre-MPI_Init datatype initialization\n\
833                 \n\
834                 Application attempted to initialize datatype of #[derive(Equivalence)] for \
835                 `{}` before initializing rsmpi. You must first initialize rsmpi before attempting \
836                 to use a custom type in an MPI call.\n",
837                type_name
838            );
839        }
840
841        let universe_state = universe_state.as_ref().unwrap();
842
843        if crate::environment::is_finalized() {
844            panic!(
845                "\n\
846                 RSMPI PANIC: Post-MPI_Finalize datatype initialization.\n\
847                 \n\
848                 Application attempted to initialize datatype of #[derive(Equivalence)] for \
849                 `{0}` after finalizing rsmpi. You must not attempt to use `{0}` in an MPI context \
850                 after finalizing rsmpi.\n",
851                type_name
852            );
853        }
854
855        if crate::environment::threading_support() != crate::Threading::Multiple
856            && universe_state.main_thread != std::thread::current().id()
857        {
858            panic!(
859                "\n\
860                 RSMPI PANIC: Invalid threaded datatype initialization\n\
861                 \n\
862                 Application attempted to initialize the datatype of #[derive(Equivalence)]
863                 for `{0}` from a different thread than that which initialized `rsmpi`. This \
864                 is only supported when rsmpi is initialized with \
865                 `mpi::Threading::Multiple`. Please explicitly call \
866                 `{0}::equivalent_datatype()` at least once from the same thread as you call \
867                 `rsmpi::initialize*`, or initialize MPI using \
868                 `mpi::initialize_with_threading(mpi::Threading::Multiple)`.\n",
869                type_name
870            )
871        }
872    }
873}
874
875/// A countable collection of things.
876pub unsafe trait Collection {
877    /// How many things are in this collection.
878    fn count(&self) -> Count;
879}
880
881unsafe impl<T> Collection for T
882where
883    T: Equivalence,
884{
885    fn count(&self) -> Count {
886        1
887    }
888}
889
890unsafe impl<T> Collection for [T]
891where
892    T: Equivalence,
893{
894    fn count(&self) -> Count {
895        self.len()
896            .value_as()
897            .expect("Length of slice cannot be expressed as an MPI Count.")
898    }
899}
900
901unsafe impl<T> Collection for Vec<T>
902where
903    T: Equivalence,
904{
905    fn count(&self) -> Count {
906        self.len()
907            .value_as()
908            .expect("Length of slice cannot be expressed as an MPI Count.")
909    }
910}
911
912unsafe impl<T, const D: usize> Collection for [T; D]
913where
914    T: Equivalence,
915{
916    fn count(&self) -> Count {
917        // TODO const generic bound
918        D.value_as()
919            .expect("Length of slice cannot be expressed as an MPI Count.")
920    }
921}
922
923/// Provides a pointer to the starting address in memory.
924pub unsafe trait Pointer {
925    /// A pointer to the starting address in memory
926    fn pointer(&self) -> *const c_void;
927}
928
929unsafe impl<T> Pointer for T
930where
931    T: Equivalence,
932{
933    fn pointer(&self) -> *const c_void {
934        let p: *const T = self;
935        p as *const c_void
936    }
937}
938
939unsafe impl<T> Pointer for [T]
940where
941    T: Equivalence,
942{
943    fn pointer(&self) -> *const c_void {
944        self.as_ptr() as _
945    }
946}
947
948unsafe impl<T> Pointer for Vec<T>
949where
950    T: Equivalence,
951{
952    fn pointer(&self) -> *const c_void {
953        self.as_ptr() as _
954    }
955}
956
957unsafe impl<T, const D: usize> Pointer for [T; D]
958where
959    T: Equivalence,
960{
961    fn pointer(&self) -> *const c_void {
962        self.as_ptr() as _
963    }
964}
965
966/// Provides a mutable pointer to the starting address in memory.
967pub unsafe trait PointerMut {
968    /// A mutable pointer to the starting address in memory
969    fn pointer_mut(&mut self) -> *mut c_void;
970}
971
972unsafe impl<T> PointerMut for T
973where
974    T: Equivalence,
975{
976    fn pointer_mut(&mut self) -> *mut c_void {
977        let p: *mut T = self;
978        p as *mut c_void
979    }
980}
981
982unsafe impl<T> PointerMut for [T]
983where
984    T: Equivalence,
985{
986    fn pointer_mut(&mut self) -> *mut c_void {
987        self.as_mut_ptr() as _
988    }
989}
990
991unsafe impl<T> PointerMut for Vec<T>
992where
993    T: Equivalence,
994{
995    fn pointer_mut(&mut self) -> *mut c_void {
996        self.as_mut_ptr() as _
997    }
998}
999
1000unsafe impl<T, const D: usize> PointerMut for [T; D]
1001where
1002    T: Equivalence,
1003{
1004    fn pointer_mut(&mut self) -> *mut c_void {
1005        self.as_mut_ptr() as _
1006    }
1007}
1008
1009/// A buffer is a region in memory that starts at `pointer()` and contains `count()` copies of
1010/// `as_datatype()`.
1011pub unsafe trait Buffer: Pointer + Collection + AsDatatype {}
1012unsafe impl<T> Buffer for T where T: Equivalence {}
1013unsafe impl<T> Buffer for [T] where T: Equivalence {}
1014unsafe impl<T> Buffer for Vec<T> where T: Equivalence {}
1015unsafe impl<T, const D: usize> Buffer for [T; D] where T: Equivalence {}
1016
1017/// A mutable buffer is a region in memory that starts at `pointer_mut()` and contains `count()`
1018/// copies of `as_datatype()`.
1019pub unsafe trait BufferMut: PointerMut + Collection + AsDatatype {}
1020unsafe impl<T> BufferMut for T where T: Equivalence {}
1021unsafe impl<T> BufferMut for [T] where T: Equivalence {}
1022unsafe impl<T> BufferMut for Vec<T> where T: Equivalence {}
1023unsafe impl<T, const D: usize> BufferMut for [T; D] where T: Equivalence {}
1024
1025/// An immutable dynamically-typed buffer.
1026///
1027/// The buffer has a definite length and MPI datatype, but it is not yet known which Rust type it
1028/// corresponds to.  This is the MPI analogue of `&Any`.  It is semantically equivalent to the trait
1029/// object reference `&Buffer`.
1030#[derive(Copy, Clone, Debug)]
1031pub struct DynBuffer<'a> {
1032    ptr: *const c_void,
1033    len: Count,
1034    datatype: DatatypeRef<'a>,
1035}
1036
1037unsafe impl<'a> Send for DynBuffer<'a> {}
1038
1039unsafe impl<'a> Sync for DynBuffer<'a> {}
1040
1041unsafe impl<'a> Collection for DynBuffer<'a> {
1042    fn count(&self) -> Count {
1043        self.len
1044    }
1045}
1046
1047unsafe impl<'a> Pointer for DynBuffer<'a> {
1048    fn pointer(&self) -> *const c_void {
1049        self.ptr
1050    }
1051}
1052
1053unsafe impl<'a> AsDatatype for DynBuffer<'a> {
1054    type Out = DatatypeRef<'a>;
1055    fn as_datatype(&self) -> Self::Out {
1056        self.datatype
1057    }
1058}
1059
1060unsafe impl<'a> Buffer for DynBuffer<'a> {}
1061
1062impl<'a> DynBuffer<'a> {
1063    /// Creates a buffer from a slice with whose type has an MPI equivalent.
1064    pub fn new<T: Equivalence>(buf: &'a [T]) -> Self {
1065        unsafe {
1066            let datatype = DatatypeRef::from_raw(T::equivalent_datatype().as_raw());
1067            Self::from_raw(buf.as_ptr(), buf.count(), datatype)
1068        }
1069    }
1070
1071    /// Tests whether the buffer type matches `T`.
1072    pub fn is<T: Equivalence>(&self) -> bool {
1073        self.as_datatype().as_raw() == T::equivalent_datatype().as_raw()
1074    }
1075
1076    /// Returns some slice if the type matches `T`, or `None` if it doesn't.
1077    pub fn downcast<T: Equivalence>(self) -> Option<&'a [T]> {
1078        if self.is::<T>() {
1079            unsafe { Some(slice::from_raw_parts(self.as_ptr() as _, self.len())) }
1080        } else {
1081            None
1082        }
1083    }
1084
1085    /// Creates a buffer from its raw components.  The buffer must remain valid for `'a` and the
1086    /// pointer must not be null.
1087    ///
1088    /// # Safety
1089    /// - Buffer pointed to by `ptr` must live as long as `'a`
1090    /// - `ptr` must point to an object that holds `len` elements of the type described by
1091    ///   `datatype`.
1092    pub unsafe fn from_raw<T>(ptr: *const T, len: Count, datatype: DatatypeRef<'a>) -> Self {
1093        debug_assert!(!ptr.is_null());
1094        Self {
1095            ptr: ptr as _,
1096            len,
1097            datatype,
1098        }
1099    }
1100
1101    /// Returns the number of elements in the buffer.
1102    pub fn len(&self) -> usize {
1103        self.count()
1104            .value_as()
1105            .expect("Length of DynBuffer cannot be expressed as a usize")
1106    }
1107
1108    /// Returns `true` if the buffer is empty
1109    pub fn is_empty(&self) -> bool {
1110        self.len() == 0
1111    }
1112
1113    /// Returns the underlying raw pointer.
1114    pub fn as_ptr(&self) -> *const c_void {
1115        self.ptr
1116    }
1117}
1118
1119/// A mutable dynamically-typed buffer.
1120///
1121/// The buffer has a definite length and MPI datatype, but it is not yet known which Rust type it
1122/// corresponds to.  This is the MPI analogue of `&mut Any`.  It is semantically equivalent to the
1123/// mutable trait object reference `&mut BufferMut`.
1124#[derive(Debug)]
1125pub struct DynBufferMut<'a> {
1126    ptr: *mut c_void,
1127    len: Count,
1128    datatype: DatatypeRef<'a>,
1129}
1130
1131unsafe impl<'a> Send for DynBufferMut<'a> {}
1132
1133unsafe impl<'a> Sync for DynBufferMut<'a> {}
1134
1135unsafe impl<'a> Collection for DynBufferMut<'a> {
1136    fn count(&self) -> Count {
1137        self.len
1138    }
1139}
1140
1141unsafe impl<'a> Pointer for DynBufferMut<'a> {
1142    fn pointer(&self) -> *const c_void {
1143        self.ptr
1144    }
1145}
1146
1147unsafe impl<'a> PointerMut for DynBufferMut<'a> {
1148    fn pointer_mut(&mut self) -> *mut c_void {
1149        self.ptr
1150    }
1151}
1152
1153unsafe impl<'a> Buffer for DynBufferMut<'a> {}
1154
1155unsafe impl<'a> BufferMut for DynBufferMut<'a> {}
1156
1157unsafe impl<'a> AsDatatype for DynBufferMut<'a> {
1158    type Out = DatatypeRef<'a>;
1159    fn as_datatype(&self) -> Self::Out {
1160        self.datatype
1161    }
1162}
1163
1164impl<'a> DynBufferMut<'a> {
1165    /// Creates a mutable buffer from a mutable slice with whose type has an MPI equivalent.
1166    pub fn new<T: Equivalence>(buf: &'a mut [T]) -> Self {
1167        unsafe {
1168            let datatype = DatatypeRef::from_raw(T::equivalent_datatype().as_raw());
1169            Self::from_raw(buf.as_mut_ptr(), buf.count(), datatype)
1170        }
1171    }
1172
1173    /// Tests whether the buffer type matches `T`.
1174    pub fn is<T: Equivalence>(&self) -> bool {
1175        self.as_datatype().as_raw() == T::equivalent_datatype().as_raw()
1176    }
1177
1178    /// Returns some mutable slice if the type matches `T`, or `None` if it doesn't.
1179    pub fn downcast<T: Equivalence>(mut self) -> Option<&'a mut [T]> {
1180        if self.is::<T>() {
1181            unsafe {
1182                Some(slice::from_raw_parts_mut(
1183                    self.as_mut_ptr() as _,
1184                    self.len(),
1185                ))
1186            }
1187        } else {
1188            None
1189        }
1190    }
1191
1192    /// Creates a buffer from its raw components.  The buffer must remain valid for `'a` and the
1193    /// pointer must not be null.
1194    ///
1195    /// # Safety
1196    /// - Buffer pointed to by `ptr` must live as long as `'a`. There must be no other
1197    ///   live reference to the buffer in Rust.
1198    /// - `ptr` must point to an object that holds `len` elements of the type described by
1199    ///   `datatype`.
1200    pub unsafe fn from_raw<T>(ptr: *mut T, len: Count, datatype: DatatypeRef<'a>) -> Self {
1201        debug_assert!(!ptr.is_null());
1202        Self {
1203            ptr: ptr as _,
1204            len,
1205            datatype,
1206        }
1207    }
1208
1209    /// Returns the number of elements in the buffer.
1210    pub fn len(&self) -> usize {
1211        self.count()
1212            .value_as()
1213            .expect("Length of DynBufferMut cannot be expressed as a usize")
1214    }
1215
1216    /// Returns `true` if the buffer is empty
1217    pub fn is_empty(&self) -> bool {
1218        self.len() == 0
1219    }
1220
1221    /// Returns the underlying raw pointer.
1222    pub fn as_ptr(&self) -> *const c_void {
1223        self.ptr
1224    }
1225
1226    /// Returns the underlying raw pointer.
1227    pub fn as_mut_ptr(&mut self) -> *mut c_void {
1228        self.ptr
1229    }
1230
1231    /// Reborrows the buffer with a shorter lifetime.
1232    pub fn reborrow(&self) -> DynBuffer {
1233        unsafe { DynBuffer::from_raw(self.as_ptr(), self.count(), self.as_datatype()) }
1234    }
1235
1236    /// Reborrows the buffer mutably with a shorter lifetime.
1237    pub fn reborrow_mut(&mut self) -> DynBufferMut {
1238        unsafe { DynBufferMut::from_raw(self.as_mut_ptr(), self.count(), self.as_datatype()) }
1239    }
1240
1241    /// Makes the buffer immutable.
1242    pub fn downgrade(self) -> DynBuffer<'a> {
1243        unsafe { DynBuffer::from_raw(self.as_ptr(), self.count(), self.as_datatype()) }
1244    }
1245}
1246
1247/// A buffer with a user specified count and datatype
1248///
1249/// # Safety
1250///
1251/// Views can be used to instruct the underlying MPI library to rummage around at arbitrary
1252/// locations in memory. This might be controlled later on using datatype bounds an slice lengths
1253/// but for now, all View constructors are marked `unsafe`.
1254pub struct View<'d, 'b, D, B: ?Sized>
1255where
1256    D: 'd + Datatype,
1257    B: 'b + Pointer,
1258{
1259    datatype: &'d D,
1260    count: Count,
1261    buffer: &'b B,
1262}
1263
1264impl<'d, 'b, D, B: ?Sized> View<'d, 'b, D, B>
1265where
1266    D: 'd + Datatype,
1267    B: 'b + Pointer,
1268{
1269    /// Return a view of `buffer` containing `count` instances of MPI datatype `datatype`.
1270    ///
1271    /// # Examples
1272    /// See `examples/contiguous.rs`, `examples/vector.rs`
1273    ///
1274    /// # Safety
1275    /// - `datatype` must map an element of `buffer` without exposing any padding bytes or
1276    ///   exceeding the bounds of the object.
1277    pub unsafe fn with_count_and_datatype(
1278        buffer: &'b B,
1279        count: Count,
1280        datatype: &'d D,
1281    ) -> View<'d, 'b, D, B> {
1282        View {
1283            datatype,
1284            count,
1285            buffer,
1286        }
1287    }
1288}
1289
1290unsafe impl<'d, 'b, D, B: ?Sized> AsDatatype for View<'d, 'b, D, B>
1291where
1292    D: 'd + Datatype,
1293    B: 'b + Pointer,
1294{
1295    type Out = &'d D;
1296    fn as_datatype(&self) -> Self::Out {
1297        self.datatype
1298    }
1299}
1300
1301unsafe impl<'d, 'b, D, B: ?Sized> Collection for View<'d, 'b, D, B>
1302where
1303    D: 'd + Datatype,
1304    B: 'b + Pointer,
1305{
1306    fn count(&self) -> Count {
1307        self.count
1308    }
1309}
1310
1311unsafe impl<'d, 'b, D, B: ?Sized> Pointer for View<'d, 'b, D, B>
1312where
1313    D: 'd + Datatype,
1314    B: 'b + Pointer,
1315{
1316    fn pointer(&self) -> *const c_void {
1317        self.buffer.pointer()
1318    }
1319}
1320
1321unsafe impl<'d, 'b, D, B: ?Sized> Buffer for View<'d, 'b, D, B>
1322where
1323    D: 'd + Datatype,
1324    B: 'b + Pointer,
1325{
1326}
1327
1328/// A buffer with a user specified count and datatype
1329///
1330/// # Safety
1331///
1332/// Views can be used to instruct the underlying MPI library to rummage around at arbitrary
1333/// locations in memory. This might be controlled later on using datatype bounds an slice lengths
1334/// but for now, all View constructors are marked `unsafe`.
1335pub struct MutView<'d, 'b, D, B: ?Sized>
1336where
1337    D: 'd + Datatype,
1338    B: 'b + PointerMut,
1339{
1340    datatype: &'d D,
1341    count: Count,
1342    buffer: &'b mut B,
1343}
1344
1345impl<'d, 'b, D, B: ?Sized> MutView<'d, 'b, D, B>
1346where
1347    D: 'd + Datatype,
1348    B: 'b + PointerMut,
1349{
1350    /// Return a view of `buffer` containing `count` instances of MPI datatype `datatype`.
1351    ///
1352    /// # Examples
1353    /// See `examples/contiguous.rs`, `examples/vector.rs`
1354    ///
1355    /// # Safety
1356    /// - `datatype` must map an element of `buffer` without exposing any padding bytes or
1357    ///   exceeding the bounds of the object.
1358    pub unsafe fn with_count_and_datatype(
1359        buffer: &'b mut B,
1360        count: Count,
1361        datatype: &'d D,
1362    ) -> MutView<'d, 'b, D, B> {
1363        MutView {
1364            datatype,
1365            count,
1366            buffer,
1367        }
1368    }
1369}
1370
1371unsafe impl<'d, 'b, D, B: ?Sized> AsDatatype for MutView<'d, 'b, D, B>
1372where
1373    D: 'd + Datatype,
1374    B: 'b + PointerMut,
1375{
1376    type Out = &'d D;
1377    fn as_datatype(&self) -> Self::Out {
1378        self.datatype
1379    }
1380}
1381
1382unsafe impl<'d, 'b, D, B: ?Sized> Collection for MutView<'d, 'b, D, B>
1383where
1384    D: 'd + Datatype,
1385    B: 'b + PointerMut,
1386{
1387    fn count(&self) -> Count {
1388        self.count
1389    }
1390}
1391
1392unsafe impl<'d, 'b, D, B: ?Sized> PointerMut for MutView<'d, 'b, D, B>
1393where
1394    D: 'd + Datatype,
1395    B: 'b + PointerMut,
1396{
1397    fn pointer_mut(&mut self) -> *mut c_void {
1398        self.buffer.pointer_mut()
1399    }
1400}
1401
1402unsafe impl<'d, 'b, D, B: ?Sized> BufferMut for MutView<'d, 'b, D, B>
1403where
1404    D: 'd + Datatype,
1405    B: 'b + PointerMut,
1406{
1407}
1408
1409/// Describes how a `Buffer` is partitioned by specifying the count of elements and displacement
1410/// from the start of the buffer for each partition.
1411pub trait Partitioned {
1412    /// The count of elements in each partition.
1413    fn counts(&self) -> &[Count];
1414    /// The displacement from the start of the buffer for each partition.
1415    fn displs(&self) -> &[Count];
1416}
1417
1418/// A buffer that is `Partitioned`
1419pub trait PartitionedBuffer: Partitioned + Pointer + AsDatatype {}
1420
1421/// A mutable buffer that is `Partitioned`
1422pub trait PartitionedBufferMut: Partitioned + PointerMut + AsDatatype {}
1423
1424/// Adds a partitioning to an existing `Buffer` so that it becomes `Partitioned`
1425pub struct Partition<'b, B: 'b + ?Sized, C, D> {
1426    buf: &'b B,
1427    counts: C,
1428    displs: D,
1429}
1430
1431impl<'b, B: ?Sized, C, D> Partition<'b, B, C, D>
1432where
1433    B: 'b + Buffer,
1434    C: Borrow<[Count]>,
1435    D: Borrow<[Count]>,
1436{
1437    /// Partition `buf` using `counts` and `displs`
1438    pub fn new(buf: &B, counts: C, displs: D) -> Partition<B, C, D> {
1439        let n = buf.count();
1440        assert!(counts
1441            .borrow()
1442            .iter()
1443            .zip(displs.borrow().iter())
1444            .all(|(&c, &d)| c + d <= n));
1445
1446        Partition {
1447            buf,
1448            counts,
1449            displs,
1450        }
1451    }
1452}
1453
1454unsafe impl<'b, B: ?Sized, C, D> AsDatatype for Partition<'b, B, C, D>
1455where
1456    B: 'b + AsDatatype,
1457{
1458    type Out = <B as AsDatatype>::Out;
1459    fn as_datatype(&self) -> Self::Out {
1460        self.buf.as_datatype()
1461    }
1462}
1463
1464unsafe impl<'b, B: ?Sized, C, D> Pointer for Partition<'b, B, C, D>
1465where
1466    B: 'b + Pointer,
1467{
1468    fn pointer(&self) -> *const c_void {
1469        self.buf.pointer()
1470    }
1471}
1472
1473impl<'b, B: ?Sized, C, D> Partitioned for Partition<'b, B, C, D>
1474where
1475    B: 'b,
1476    C: Borrow<[Count]>,
1477    D: Borrow<[Count]>,
1478{
1479    fn counts(&self) -> &[Count] {
1480        self.counts.borrow()
1481    }
1482    fn displs(&self) -> &[Count] {
1483        self.displs.borrow()
1484    }
1485}
1486
1487impl<'b, B: ?Sized, C, D> PartitionedBuffer for Partition<'b, B, C, D>
1488where
1489    B: 'b + Pointer + AsDatatype,
1490    C: Borrow<[Count]>,
1491    D: Borrow<[Count]>,
1492{
1493}
1494
1495/// Adds a partitioning to an existing `BufferMut` so that it becomes `Partitioned`
1496pub struct PartitionMut<'b, B: 'b + ?Sized, C, D> {
1497    buf: &'b mut B,
1498    counts: C,
1499    displs: D,
1500}
1501
1502impl<'b, B: ?Sized, C, D> PartitionMut<'b, B, C, D>
1503where
1504    B: 'b + BufferMut,
1505    C: Borrow<[Count]>,
1506    D: Borrow<[Count]>,
1507{
1508    /// Partition `buf` using `counts` and `displs`
1509    pub fn new(buf: &mut B, counts: C, displs: D) -> PartitionMut<B, C, D> {
1510        let n = buf.count();
1511        assert!(counts
1512            .borrow()
1513            .iter()
1514            .zip(displs.borrow().iter())
1515            .all(|(&c, &d)| c + d <= n));
1516
1517        PartitionMut {
1518            buf,
1519            counts,
1520            displs,
1521        }
1522    }
1523}
1524
1525unsafe impl<'b, B: ?Sized, C, D> AsDatatype for PartitionMut<'b, B, C, D>
1526where
1527    B: 'b + AsDatatype,
1528{
1529    type Out = <B as AsDatatype>::Out;
1530    fn as_datatype(&self) -> Self::Out {
1531        self.buf.as_datatype()
1532    }
1533}
1534
1535unsafe impl<'b, B: ?Sized, C, D> PointerMut for PartitionMut<'b, B, C, D>
1536where
1537    B: 'b + PointerMut,
1538{
1539    fn pointer_mut(&mut self) -> *mut c_void {
1540        self.buf.pointer_mut()
1541    }
1542}
1543
1544impl<'b, B: ?Sized, C, D> Partitioned for PartitionMut<'b, B, C, D>
1545where
1546    B: 'b,
1547    C: Borrow<[Count]>,
1548    D: Borrow<[Count]>,
1549{
1550    fn counts(&self) -> &[Count] {
1551        self.counts.borrow()
1552    }
1553    fn displs(&self) -> &[Count] {
1554        self.displs.borrow()
1555    }
1556}
1557
1558impl<'b, B: ?Sized, C, D> PartitionedBufferMut for PartitionMut<'b, B, C, D>
1559where
1560    B: 'b + PointerMut + AsDatatype,
1561    C: Borrow<[Count]>,
1562    D: Borrow<[Count]>,
1563{
1564}
1565
1566/// Returns the address of the argument in a format suitable for use with datatype constructors
1567///
1568/// # Examples
1569/// See `examples/structured.rs`
1570///
1571/// # Standard section(s)
1572///
1573/// 4.1.5
1574pub fn address_of<T>(x: &T) -> Address {
1575    let x: *const T = x;
1576    unsafe { with_uninitialized(|address| ffi::MPI_Get_address(x as *const c_void, address)).1 }
1577}