Skip to main content

tskit/
site_table.rs

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