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;
9
10/// A site table.
11///
12/// # Examples
13///
14/// ```
15/// use tskit::SiteTable;
16///
17/// let mut sites = SiteTable::default();
18/// let rowid = sites.add_row(1., None).unwrap();
19/// assert_eq!(rowid, 0);
20/// assert_eq!(sites.num_rows(), 1);
21/// ```
22///
23/// An example with metadata.
24/// This requires the cargo feature `"derive"` for `tskit`.
25///
26/// ```
27/// # #[cfg(any(feature="doc", feature="derive"))] {
28/// use tskit::SiteTable;
29///
30/// #[derive(serde::Serialize,
31///          serde::Deserialize,
32///          tskit::metadata::SiteMetadata)]
33/// #[serializer("serde_json")]
34/// struct SiteMetadata {
35///     value: i32,
36/// }
37///
38/// let metadata = SiteMetadata{value: 42};
39///
40/// let mut sites = SiteTable::default();
41///
42/// let rowid = sites.add_row_with_metadata(0., None, &metadata).unwrap();
43/// assert_eq!(rowid, 0);
44///
45/// match sites.metadata::<SiteMetadata>(rowid) {
46///     // rowid is in range, decoding succeeded
47///     Some(Ok(decoded)) => assert_eq!(decoded.value, 42),
48///     // rowid is in range, decoding failed
49///     Some(Err(e)) => panic!("error decoding metadata: {:?}", e),
50///     None => panic!("row id out of range")
51/// }
52/// # }
53/// ```
54#[derive(Debug, Default)]
55#[repr(transparent)]
56pub struct SiteTable {
57    table_: sys::SiteTable,
58}
59
60impl SiteTable {
61    // # Safety
62    //
63    // * this fn must NEVER by part of the public API
64    // * all returned values must only be visible to the public API
65    //   by REFERENCE (& or &mut)
66    // * the input ptr must not be NULL
67    // * the input ptr must point to an initialized table
68    pub(crate) unsafe fn new_from_table(
69        sites: *mut ll_bindings::tsk_site_table_t,
70    ) -> Result<Self, TskitError> {
71        let ptr = std::ptr::NonNull::new(sites).unwrap();
72        let table_ = unsafe { sys::SiteTable::new_borrowed(ptr) };
73        Ok(SiteTable { table_ })
74    }
75
76    pub(crate) fn as_ref(&self) -> &ll_bindings::tsk_site_table_t {
77        self.table_.as_ref()
78    }
79
80    /// Return the number of rows
81    pub fn num_rows(&self) -> SizeType {
82        self.as_ref().num_rows.into()
83    }
84
85    /// Return the ``position`` value from row ``row`` of the table.
86    ///
87    /// # Returns
88    ///
89    /// * `Some(position)` if `row` is valid.
90    /// * `None` otherwise.
91    pub fn position<S: Into<SiteId> + Copy>(&self, row: S) -> Option<Position> {
92        self.table_.position(row.into())
93    }
94
95    /// Get the ``ancestral_state`` value from row ``row`` of the table.
96    ///
97    /// # Returns
98    ///
99    /// * `Some(ancestral state)` if `row` is valid.
100    /// * `None` otherwise.
101    pub fn ancestral_state<S: Into<SiteId>>(&self, row: S) -> Option<&[u8]> {
102        self.table_.ancestral_state(row.into())
103    }
104
105    /// Retrieve decoded metadata for a `row`.
106    ///
107    /// # Returns
108    ///
109    /// * `Some(Ok(T))` if `row` is valid and decoding succeeded.
110    /// * `Some(Err(_))` if `row` is valid and decoding failed.
111    /// * `None` if `row` is not valid or the row has no metadata.
112    ///
113    /// # Errors
114    ///
115    /// * [`TskitError::MetadataError`] if decoding fails.
116    ///
117    /// # Examples.
118    ///
119    /// The big-picture semantics are the same for all table types.
120    /// See [`crate::IndividualTable::metadata`] for examples.
121    pub fn metadata<T: metadata::SiteMetadata>(
122        &self,
123        row: impl Into<SiteId>,
124    ) -> Option<Result<T, TskitError>> {
125        let buffer = self.table_.raw_metadata(row)?;
126        Some(decode_metadata_row!(T, buffer).map_err(TskitError::from))
127    }
128
129    /// Return an iterator over rows of the table.
130    /// The value of the iterator is [`crate::Site`].
131    pub fn iter(&self) -> impl Iterator<Item = crate::Site<'_>> {
132        self.table_.iter()
133    }
134
135    /// Return row `r` of the table.
136    ///
137    /// # Parameters
138    ///
139    /// * `r`: the row id.
140    ///
141    /// # Returns
142    ///
143    /// * `Some(row)` if `r` is valid
144    /// * `None` otherwise
145    pub fn row<S: Into<SiteId> + Copy>(&self, r: S) -> Option<super::Site<'_>> {
146        self.table_.row(r.into())
147    }
148
149    build_table_column_slice_getter!(
150        /// Get the position column as a slice
151        => position, position_slice, Position);
152    build_table_column_slice_getter!(
153        /// Get the position column as a slice
154        => position, position_slice_raw, f64);
155
156    pub fn position_column(&self) -> impl crate::TableColumn<SiteId, Position> + '_ {
157        crate::table_column::OpaqueTableColumn(self.position_slice())
158    }
159
160    /// Clear all data from the table
161    pub fn clear(&mut self) -> Result<i32, TskitError> {
162        handle_tsk_return_value!(self.table_.clear())
163    }
164
165    pub fn add_row<P: Into<Position>>(
166        &mut self,
167        position: P,
168        ancestral_state: Option<&[u8]>,
169    ) -> Result<SiteId, TskitError> {
170        let rv = self
171            .table_
172            .add_row(position.into().into(), ancestral_state)?;
173        handle_tsk_return_value!(rv, rv.into())
174    }
175
176    pub fn add_row_with_metadata<P: Into<Position>, M: SiteMetadata>(
177        &mut self,
178        position: P,
179        ancestral_state: Option<&[u8]>,
180        metadata: &M,
181    ) -> Result<SiteId, TskitError> {
182        let md = crate::metadata::EncodedMetadata::new(metadata)?;
183        let rv = self.table_.add_row_with_metadata(
184            position.into().into(),
185            ancestral_state,
186            md.as_slice(),
187        )?;
188        handle_tsk_return_value!(rv, rv.into())
189    }
190}