ndgrid/traits/io/
ron.rs

1//! RON I/O
2use crate::traits::Grid;
3#[cfg(feature = "mpi")]
4use crate::traits::ParallelGrid;
5#[cfg(feature = "mpi")]
6use mpi::traits::Communicator;
7use std::fs;
8
9pub trait ConvertToSerializable {
10    //! Convert to/from a RON string
11    type SerializableType: serde::Serialize;
12    /// Convert to ron
13    fn to_serializable(&self) -> Self::SerializableType;
14    /// Convert from ron
15    fn from_serializable(ron: Self::SerializableType) -> Self;
16}
17
18pub trait RONExport: Grid {
19    //! Grid export for RON
20
21    /// Generate the RON string for a grid
22    fn to_ron_string(&self) -> String;
23
24    /// Export as RON
25    fn export_as_ron(&self, filename: &str) {
26        let ron_s = self.to_ron_string();
27        fs::write(filename, ron_s).expect("Unable to write file");
28    }
29}
30
31pub trait RONImport: Sized + Grid {
32    //! Grid import for RON
33
34    /// Generate grid from a RON string
35    fn from_ron_string(s: String) -> Self;
36
37    /// Import from RON
38    fn import_from_ron(filename: &str) -> Self {
39        let content = fs::read_to_string(filename).expect("Unable to read file");
40        Self::from_ron_string(content)
41    }
42}
43
44#[cfg(feature = "mpi")]
45#[derive(Debug, serde::Serialize, serde::Deserialize)]
46/// Summary I/O data for a parallel grid
47pub struct ParallelGridSummaryData {
48    mpi_ranks: i32,
49}
50
51#[cfg(feature = "mpi")]
52pub trait RONExportParallel<'a, C: Communicator + 'a>: ParallelGrid<C = C>
53where
54    Self::LocalGrid: RONExport,
55    Self: 'a,
56{
57    //! Parallel grid export for RON
58
59    /// Export as RON
60    fn export_as_ron(&'a self, filename: &str) {
61        let parts = filename.split('.').collect::<Vec<_>>();
62        assert!(parts.len() > 1);
63        let sub_filename = format!(
64            "{}.{}.{}",
65            parts[0..parts.len() - 1].join("."),
66            self.comm().rank(),
67            parts[parts.len() - 1]
68        );
69
70        self.local_grid().export_as_ron(&sub_filename);
71        if self.comm().rank() == 0 {
72            let grid_data = ParallelGridSummaryData {
73                mpi_ranks: self.comm().size(),
74            };
75            fs::write(filename, ron::to_string(&grid_data).unwrap()).expect("Unable to write file");
76        }
77    }
78}
79
80#[cfg(feature = "mpi")]
81pub trait RONImportParallel<'a, C: Communicator + 'a>: Sized + ParallelGrid<C = C>
82where
83    Self::LocalGrid: RONImport,
84    Self: 'a,
85{
86    //! Parallel grid import for RON
87
88    /// Create parallel grid from comm and local_grid
89    fn create_from_ron_info(comm: &'a C, local_grid: Self::LocalGrid) -> Self;
90
91    /// Export as RON
92    fn import_from_ron(comm: &'a C, filename: &str) -> Self {
93        let parts = filename.split('.').collect::<Vec<_>>();
94        assert!(parts.len() > 1);
95        let sub_filename = format!(
96            "{}.{}.{}",
97            parts[0..parts.len() - 1].join("."),
98            comm.rank(),
99            parts[parts.len() - 1]
100        );
101
102        let content = fs::read_to_string(filename).expect("Unable to read file");
103        let summary: ParallelGridSummaryData = ron::from_str(&content).unwrap();
104
105        if summary.mpi_ranks != comm.size() {
106            panic!("Incorrect number of MPI ranks");
107        }
108
109        let local_grid = Self::LocalGrid::import_from_ron(&sub_filename);
110        Self::create_from_ron_info(comm, local_grid)
111    }
112}