Skip to main content

henad_explore/output/
memory.rs

1//! Files of a sweep or search held in memory, byte for byte the files an output directory would hold.
2
3use std::path::Path;
4use std::sync::Arc;
5
6use henad_core::explore::measure::MeasurePlan;
7use henad_core::explore::plan::Plan;
8use henad_core::params::ParamDescriptor;
9
10use crate::output::manifest::Manifest;
11use crate::output::runs_csv::RunsWriter;
12use crate::output::series_csv::SeriesWriter;
13use crate::output::summary_csv::{SummaryError, write_summary};
14use crate::output::{
15    MANIFEST_FILE, OutputError, OutputWriter, RUNS_FILE, SERIES_FILE, SUMMARY_FILE, manifest_text, write_error_at,
16};
17
18/// The four files of a sweep, and the tables a search adds.
19#[derive(Debug, Clone, Default, PartialEq, Eq)]
20pub struct SweepFiles {
21    /// Bytes of `runs.csv`.
22    pub runs: Vec<u8>,
23    /// Bytes of `series.csv`.
24    pub series: Vec<u8>,
25    /// Bytes of `summary.csv`.
26    pub summary: Vec<u8>,
27    /// Bytes of `manifest.json`.
28    pub manifest: Vec<u8>,
29    /// Tables a search writes, each with its file name, in the order they are listed. Empty for a sweep.
30    pub search_tables: Vec<(&'static str, Vec<u8>)>,
31}
32
33impl SweepFiles {
34    /// Returns the files of the runs `writer` holds, with `summary.csv` rebuilt from them and `manifest` as
35    /// `manifest.json`.
36    ///
37    /// # Errors
38    ///
39    /// Returns [`OutputError::Summary`] when the runs cannot be summarized, [`OutputError::Read`] when they are not
40    /// UTF-8, and [`OutputError::Manifest`] when the manifest cannot be serialized.
41    pub(crate) fn assemble(writer: OutputWriter<Vec<u8>>, manifest: &Manifest) -> Result<Self, OutputError> {
42        let (runs, series) = writer.finish().map_err(write_error_at(Path::new(RUNS_FILE)))?;
43        let summary = match write_summary(runs.as_slice(), Vec::new()) {
44            Ok(summary) => summary,
45            Err(SummaryError::Read(source)) => {
46                return Err(OutputError::Read {
47                    path: Path::new(RUNS_FILE).to_owned(),
48                    source,
49                });
50            }
51            Err(SummaryError::Io(source)) => return Err(write_error_at(Path::new(SUMMARY_FILE))(source)),
52            Err(error) => return Err(OutputError::Summary(error)),
53        };
54        Ok(Self {
55            runs,
56            series,
57            summary,
58            manifest: manifest_text(manifest)?.into_bytes(),
59            search_tables: Vec::new(),
60        })
61    }
62
63    /// Returns each file with its name in an output directory, in the order runs, series, summary and manifest, then
64    /// the search tables.
65    pub fn entries(&self) -> Vec<(&'static str, &[u8])> {
66        let mut entries: Vec<(&'static str, &[u8])> = vec![
67            (RUNS_FILE, &self.runs),
68            (SERIES_FILE, &self.series),
69            (SUMMARY_FILE, &self.summary),
70            (MANIFEST_FILE, &self.manifest),
71        ];
72        entries.extend(self.search_tables.iter().map(|(name, bytes)| (*name, bytes.as_slice())));
73        entries
74    }
75
76    /// Returns each file with its name in an output directory, in the form [`crate::result_set::ResultSet::from_files`]
77    /// reads.
78    pub fn into_entries(self) -> Vec<(String, Vec<u8>)> {
79        let mut entries = vec![
80            (RUNS_FILE.to_owned(), self.runs),
81            (SERIES_FILE.to_owned(), self.series),
82            (SUMMARY_FILE.to_owned(), self.summary),
83            (MANIFEST_FILE.to_owned(), self.manifest),
84        ];
85        entries.extend(
86            self.search_tables
87                .into_iter()
88                .map(|(name, bytes)| (name.to_owned(), bytes)),
89        );
90        entries
91    }
92}
93
94/// Returns a writer for the runs of `plan` that holds `runs.csv` and `series.csv` in memory, their headers written.
95///
96/// `params` are the model's parameters, and `measure` fixes the stat and reducer columns.
97///
98/// # Errors
99///
100/// Returns [`OutputError::Write`] when a header cannot be written.
101pub(crate) fn memory_writer(
102    plan: &Arc<Plan>,
103    params: &[ParamDescriptor],
104    measure: &MeasurePlan,
105) -> Result<OutputWriter<Vec<u8>>, OutputError> {
106    let runs = RunsWriter::new(Vec::new(), params, plan.actions(), measure.reducers().names())
107        .map_err(write_error_at(Path::new(RUNS_FILE)))?;
108    let series = SeriesWriter::new(Vec::new(), measure.columns()).map_err(write_error_at(Path::new(SERIES_FILE)))?;
109    Ok(OutputWriter::new(Arc::clone(plan), runs, series))
110}