noodles_bcf/record/
samples.rs

1//! BCF record samples.
2
3mod sample;
4pub mod series;
5
6use std::{io, iter};
7
8use noodles_vcf as vcf;
9
10use self::series::read_series;
11pub use self::{sample::Sample, series::Series};
12
13/// BCF record samples.
14#[derive(Clone, Debug, Default, Eq, PartialEq)]
15pub struct Samples<'r> {
16    src: &'r [u8],
17    sample_count: usize,
18    format_count: usize,
19}
20
21impl<'r> Samples<'r> {
22    pub(super) fn new(src: &'r [u8], sample_count: usize, format_count: usize) -> Self {
23        Self {
24            src,
25            sample_count,
26            format_count,
27        }
28    }
29
30    /// Returns the number of fields per sample.
31    ///
32    /// # Examples
33    ///
34    /// ```
35    /// use noodles_bcf::record::Samples;
36    /// let samples = Samples::default();
37    /// assert_eq!(samples.format_count(), 0);
38    /// ```
39    pub fn format_count(&self) -> usize {
40        self.format_count
41    }
42
43    /// Returns the sample with the given sample name.
44    pub fn get(&'r self, header: &vcf::Header, sample_name: &str) -> Option<Sample<'r>> {
45        header
46            .sample_names()
47            .get_index_of(sample_name)
48            .and_then(|i| self.get_index(i))
49    }
50
51    /// Returns a sample at the given index.
52    pub fn get_index(&'r self, i: usize) -> Option<Sample<'r>> {
53        if i < self.sample_count {
54            Some(Sample::new(self, i))
55        } else {
56            None
57        }
58    }
59
60    /// Returns the series with the given column name.
61    pub fn select<'h: 'r>(
62        &'r self,
63        header: &'h vcf::Header,
64        column_name: &str,
65    ) -> Option<io::Result<Series<'r>>> {
66        for result in self.series() {
67            let series = match result {
68                Ok(s) => s,
69                Err(e) => return Some(Err(e)),
70            };
71
72            match series.name(header) {
73                Ok(name) if name == column_name => return Some(Ok(series)),
74                Ok(_) => {}
75                Err(e) => return Some(Err(e)),
76            }
77        }
78
79        None
80    }
81
82    /// Returns an iterator over series.
83    pub fn series(&'r self) -> impl Iterator<Item = io::Result<Series<'r>>> + 'r {
84        let mut src = self.src;
85
86        iter::from_fn(move || {
87            if src.is_empty() {
88                None
89            } else {
90                Some(read_series(&mut src, self.sample_count))
91            }
92        })
93    }
94
95    /// Returns an iterator over samples.
96    pub fn iter(&self) -> impl Iterator<Item = Sample<'_>> {
97        (0..self.sample_count).map(|i| Sample::new(self, i))
98    }
99}
100
101impl AsRef<[u8]> for Samples<'_> {
102    fn as_ref(&self) -> &[u8] {
103        self.src
104    }
105}
106
107impl vcf::variant::record::Samples for Samples<'_> {
108    fn is_empty(&self) -> bool {
109        self.len() == 0
110    }
111
112    fn len(&self) -> usize {
113        self.sample_count
114    }
115
116    fn column_names<'a, 'h: 'a>(
117        &'a self,
118        header: &'h vcf::Header,
119    ) -> Box<dyn Iterator<Item = io::Result<&'a str>> + 'a> {
120        Box::new(
121            self.series()
122                .map(|result| result.and_then(|series| series.name(header))),
123        )
124    }
125
126    fn select<'a, 'h: 'a>(
127        &'a self,
128        header: &'h vcf::Header,
129        column_name: &str,
130    ) -> Option<io::Result<Box<dyn vcf::variant::record::samples::Series + 'a>>> {
131        self.select(header, column_name).map(|result| {
132            result.map(|series| Box::new(series) as Box<dyn vcf::variant::record::samples::Series>)
133        })
134    }
135
136    fn series(
137        &self,
138    ) -> Box<
139        dyn Iterator<Item = io::Result<Box<dyn vcf::variant::record::samples::Series + '_>>> + '_,
140    > {
141        Box::new(self.series().map(|result| {
142            result.map(|series| Box::new(series) as Box<dyn vcf::variant::record::samples::Series>)
143        }))
144    }
145
146    fn iter(
147        &self,
148    ) -> Box<dyn Iterator<Item = Box<dyn vcf::variant::record::samples::Sample + '_>> + '_> {
149        Box::new(
150            self.iter()
151                .map(|sample| Box::new(sample) as Box<dyn vcf::variant::record::samples::Sample>),
152        )
153    }
154}