Skip to main content

data_beans/sparse_io/
meta.rs

1//! Metadata: short strings stored with a backend that say what its data is,
2//! so a reader need not infer it from the file name. Any key may be used;
3//! the ones below are shared between the programs that write and read
4//! backends, and mean the same everywhere.
5
6// The shared keys are for the library's users; the binary copies metadata
7// through without naming them.
8#![allow(dead_code)]
9
10use std::collections::BTreeMap;
11
12/// Key → value, in key order.
13pub type Metadata = BTreeMap<String, String>;
14
15/// The root attribute that holds the metadata, in both backends.
16pub(crate) const ATTR: &str = "meta";
17
18/// The sample or batch the data comes from, e.g. `s1`. Merging backends of
19/// different samples drops it.
20pub const SAMPLE: &str = "sample";
21
22/// The program and command that wrote the data, e.g. `faba count`.
23pub const PRODUCER: &str = "producer";
24
25/// What the rows hold, e.g. [`GENE_COUNT`].
26pub const CONTENT: &str = "content";
27
28/// [`CONTENT`] of a gene count matrix, its rows named
29/// `{gene}/count/{spliced|unspliced}`.
30pub const GENE_COUNT: &str = "gene_count";
31
32/// The metadata all of `metas` agree on: each key that every one has, with
33/// the same value. Used where backends are merged, so a merge of samples
34/// keeps no [`SAMPLE`] while a merge of one sample's parts keeps it.
35pub fn common_metadata(metas: &[Metadata]) -> Metadata {
36    let Some((first, rest)) = metas.split_first() else {
37        return Metadata::new();
38    };
39    first
40        .iter()
41        .filter(|(k, v)| rest.iter().all(|m| m.get(*k) == Some(*v)))
42        .map(|(k, v)| (k.clone(), v.clone()))
43        .collect()
44}
45
46#[cfg(test)]
47mod tests;