tskit/
site_table.rs

1use crate::bindings as ll_bindings;
2use crate::metadata;
3use crate::sys;
4use crate::tsk_id_t;
5use crate::Position;
6use crate::SiteId;
7use crate::SizeType;
8use crate::TskitError;
9
10/// Row of a [`SiteTable`]
11#[derive(Debug)]
12pub struct SiteTableRow {
13    pub id: SiteId,
14    pub position: Position,
15    pub ancestral_state: Option<Vec<u8>>,
16    pub metadata: Option<Vec<u8>>,
17}
18
19impl PartialEq for SiteTableRow {
20    fn eq(&self, other: &Self) -> bool {
21        self.id == other.id
22            && crate::util::partial_cmp_equal(&self.position, &other.position)
23            && self.ancestral_state == other.ancestral_state
24            && self.metadata == other.metadata
25    }
26}
27
28fn make_site_table_row(table: &SiteTable, pos: tsk_id_t) -> Option<SiteTableRow> {
29    let ancestral_state = table.ancestral_state(pos).map(|s| s.to_vec());
30    Some(SiteTableRow {
31        id: pos.into(),
32        position: table.position(pos)?,
33        ancestral_state,
34        metadata: table.raw_metadata(pos).map(|m| m.to_vec()),
35    })
36}
37
38pub(crate) type SiteTableRefIterator<'a> = crate::table_iterator::TableIterator<&'a SiteTable>;
39pub(crate) type SiteTableIterator = crate::table_iterator::TableIterator<SiteTable>;
40
41impl<'a> Iterator for SiteTableRefIterator<'a> {
42    type Item = SiteTableRow;
43
44    fn next(&mut self) -> Option<Self::Item> {
45        let rv = make_site_table_row(self.table, self.pos);
46        self.pos += 1;
47        rv
48    }
49}
50
51impl Iterator for SiteTableIterator {
52    type Item = SiteTableRow;
53
54    fn next(&mut self) -> Option<Self::Item> {
55        let rv = make_site_table_row(&self.table, self.pos);
56        self.pos += 1;
57        rv
58    }
59}
60
61#[derive(Debug)]
62pub struct SiteTableRowView<'a> {
63    table: &'a SiteTable,
64    pub id: SiteId,
65    pub position: Position,
66    pub ancestral_state: Option<&'a [u8]>,
67    pub metadata: Option<&'a [u8]>,
68}
69
70impl<'a> SiteTableRowView<'a> {
71    fn new(table: &'a SiteTable) -> Self {
72        Self {
73            table,
74            id: SiteId::NULL,
75            position: f64::NAN.into(),
76            ancestral_state: None,
77            metadata: None,
78        }
79    }
80}
81
82impl<'a> PartialEq for SiteTableRowView<'a> {
83    fn eq(&self, other: &Self) -> bool {
84        self.id == other.id
85            && crate::util::partial_cmp_equal(&self.position, &other.position)
86            && self.ancestral_state == other.ancestral_state
87            && self.metadata == other.metadata
88    }
89}
90
91impl<'a> Eq for SiteTableRowView<'a> {}
92
93impl<'a> PartialEq<SiteTableRow> for SiteTableRowView<'a> {
94    fn eq(&self, other: &SiteTableRow) -> bool {
95        self.id == other.id
96            && crate::util::partial_cmp_equal(&self.position, &other.position)
97            && optional_container_comparison!(self.ancestral_state, other.ancestral_state)
98            && optional_container_comparison!(self.metadata, other.metadata)
99    }
100}
101
102impl PartialEq<SiteTableRowView<'_>> for SiteTableRow {
103    fn eq(&self, other: &SiteTableRowView) -> bool {
104        self.id == other.id
105            && crate::util::partial_cmp_equal(&self.position, &other.position)
106            && optional_container_comparison!(self.ancestral_state, other.ancestral_state)
107            && optional_container_comparison!(self.metadata, other.metadata)
108    }
109}
110
111impl<'a> streaming_iterator::StreamingIterator for SiteTableRowView<'a> {
112    type Item = Self;
113
114    row_lending_iterator_get!();
115
116    fn advance(&mut self) {
117        self.id = (i32::from(self.id) + 1).into();
118        self.position = self
119            .table
120            .position(self.id)
121            .unwrap_or_else(|| f64::NAN.into());
122        self.ancestral_state = self.table.ancestral_state(self.id);
123        self.metadata = self.table.raw_metadata(self.id);
124    }
125}
126
127/// An immutable view of site table.
128#[derive(Debug)]
129#[repr(transparent)]
130pub struct SiteTable {
131    table_: sys::LLSiteTableRef,
132}
133
134impl SiteTable {
135    pub(crate) fn new_from_table(
136        sites: *mut ll_bindings::tsk_site_table_t,
137    ) -> Result<Self, TskitError> {
138        let table_ = sys::LLSiteTableRef::new_from_table(sites)?;
139        Ok(SiteTable { table_ })
140    }
141
142    pub(crate) fn as_ref(&self) -> &ll_bindings::tsk_site_table_t {
143        self.table_.as_ref()
144    }
145
146    raw_metadata_getter_for_tables!(SiteId);
147
148    /// Return the number of rows
149    pub fn num_rows(&self) -> SizeType {
150        self.as_ref().num_rows.into()
151    }
152
153    /// Return the ``position`` value from row ``row`` of the table.
154    ///
155    /// # Returns
156    ///
157    /// * `Some(position)` if `row` is valid.
158    /// * `None` otherwise.
159    pub fn position<S: Into<SiteId> + Copy>(&self, row: S) -> Option<Position> {
160        sys::tsk_column_access::<Position, _, _, _>(
161            row.into(),
162            self.as_ref().position,
163            self.num_rows(),
164        )
165    }
166
167    /// Get the ``ancestral_state`` value from row ``row`` of the table.
168    ///
169    /// # Returns
170    ///
171    /// * `Some(ancestral state)` if `row` is valid.
172    /// * `None` otherwise.
173    pub fn ancestral_state<S: Into<SiteId>>(&self, row: S) -> Option<&[u8]> {
174        sys::tsk_ragged_column_access(
175            row.into(),
176            self.as_ref().ancestral_state,
177            self.num_rows(),
178            self.as_ref().ancestral_state_offset,
179            self.as_ref().ancestral_state_length,
180        )
181    }
182
183    /// Retrieve decoded metadata for a `row`.
184    ///
185    /// # Returns
186    ///
187    /// * `Some(Ok(T))` if `row` is valid and decoding succeeded.
188    /// * `Some(Err(_))` if `row` is not valid and decoding failed.
189    /// * `None` if `row` is not valid.
190    ///
191    /// # Errors
192    ///
193    /// * [`TskitError::MetadataError`] if decoding fails.
194    ///
195    /// # Examples.
196    ///
197    /// The big-picture semantics are the same for all table types.
198    /// See [`crate::IndividualTable::metadata`] for examples.
199    pub fn metadata<T: metadata::SiteMetadata>(
200        &self,
201        row: SiteId,
202    ) -> Option<Result<T, TskitError>> {
203        let buffer = self.raw_metadata(row)?;
204        Some(decode_metadata_row!(T, buffer).map_err(TskitError::from))
205    }
206
207    /// Return an iterator over rows of the table.
208    /// The value of the iterator is [`SiteTableRow`].
209    pub fn iter(&self) -> impl Iterator<Item = SiteTableRow> + '_ {
210        crate::table_iterator::make_table_iterator::<&SiteTable>(self)
211    }
212
213    pub fn lending_iter(&self) -> SiteTableRowView {
214        SiteTableRowView::new(self)
215    }
216
217    /// Return row `r` of the table.
218    ///
219    /// # Parameters
220    ///
221    /// * `r`: the row id.
222    ///
223    /// # Returns
224    ///
225    /// * `Some(row)` if `r` is valid
226    /// * `None` otherwise
227    pub fn row<S: Into<SiteId> + Copy>(&self, r: S) -> Option<SiteTableRow> {
228        let ri = r.into().into();
229        table_row_access!(ri, self, make_site_table_row)
230    }
231
232    /// Return a view of row `r` of the table.
233    ///
234    /// # Parameters
235    ///
236    /// * `r`: the row id.
237    ///
238    /// # Returns
239    ///
240    /// * `Some(row view)` if `r` is valid
241    /// * `None` otherwise
242    pub fn row_view<S: Into<SiteId> + Copy>(&self, r: S) -> Option<SiteTableRowView> {
243        let view = SiteTableRowView {
244            table: self,
245            id: r.into(),
246            position: self.position(r)?,
247            ancestral_state: self.ancestral_state(r),
248            metadata: self.raw_metadata(r.into()),
249        };
250        Some(view)
251    }
252
253    build_table_column_slice_getter!(
254        /// Get the position column as a slice
255        => position, position_slice, Position);
256    build_table_column_slice_getter!(
257        /// Get the position column as a slice
258        => position, position_slice_raw, f64);
259}
260
261build_owned_table_type!(
262    /// A standalone site table that owns its data.
263    ///
264    /// # Examples
265    ///
266    /// ```
267    /// use tskit::OwningSiteTable;
268    ///
269    /// let mut sites = OwningSiteTable::default();
270    /// let rowid = sites.add_row(1., None).unwrap();
271    /// assert_eq!(rowid, 0);
272    /// assert_eq!(sites.num_rows(), 1);
273    /// ```
274    ///
275    /// An example with metadata.
276    /// This requires the cargo feature `"derive"` for `tskit`.
277    ///
278    /// ```
279    /// # #[cfg(any(feature="doc", feature="derive"))] {
280    /// use tskit::OwningSiteTable;
281    ///
282    /// #[derive(serde::Serialize,
283    ///          serde::Deserialize,
284    ///          tskit::metadata::SiteMetadata)]
285    /// #[serializer("serde_json")]
286    /// struct SiteMetadata {
287    ///     value: i32,
288    /// }
289    ///
290    /// let metadata = SiteMetadata{value: 42};
291    ///
292    /// let mut sites = OwningSiteTable::default();
293    ///
294    /// let rowid = sites.add_row_with_metadata(0., None, &metadata).unwrap();
295    /// assert_eq!(rowid, 0);
296    ///
297    /// match sites.metadata::<SiteMetadata>(rowid) {
298    ///     // rowid is in range, decoding succeeded
299    ///     Some(Ok(decoded)) => assert_eq!(decoded.value, 42),
300    ///     // rowid is in range, decoding failed
301    ///     Some(Err(e)) => panic!("error decoding metadata: {:?}", e),
302    ///     None => panic!("row id out of range")
303    /// }
304    /// # }
305    /// ```
306    => OwningSiteTable,
307    SiteTable,
308    crate::sys::LLOwningSiteTable,
309    crate::bindings::tsk_site_table_t
310);
311
312impl OwningSiteTable {
313    site_table_add_row!(=> add_row, self, self.as_mut_ptr());
314    site_table_add_row_with_metadata!(=> add_row_with_metadata, self, self.as_mut_ptr());
315}