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}