diff --git a/examples/forward_simulation.rs b/examples/forward_simulation.rs index 9c249664b..808590429 100644 --- a/examples/forward_simulation.rs +++ b/examples/forward_simulation.rs @@ -373,7 +373,7 @@ fn update_bookmark( for a in alive { for node in [a.node0, a.node1] { match nodes.time(node) { - Ok(time) => { + Some(time) => { most_recent_birth_time = if time < most_recent_birth_time { time.into() } else { @@ -385,7 +385,7 @@ fn update_bookmark( most_ancient_birth_time }; } - Err(e) => return Err(e), + None => return Err(tskit::TskitError::IndexError {}), } } } diff --git a/src/_macros.rs b/src/_macros.rs index ed8d77817..9592dfd17 100644 --- a/src/_macros.rs +++ b/src/_macros.rs @@ -30,27 +30,33 @@ macro_rules! panic_on_tskit_error { macro_rules! unsafe_tsk_column_access { ($i: expr, $lo: expr, $hi: expr, $array: expr) => {{ if $i < $lo || ($i as $crate::tsk_size_t) >= $hi { - Err($crate::error::TskitError::IndexError {}) + None } else { - Ok(unsafe { *$array.offset($i as isize) }) + Some(unsafe { *$array.offset($i as isize) }) } }}; ($i: expr, $lo: expr, $hi: expr, $array: expr, $output_id_type: expr) => {{ if $i < $lo || ($i as $crate::tsk_size_t) >= $hi { - Err($crate::error::TskitError::IndexError {}) + None } else { - Ok($output_id_type(unsafe { *$array.offset($i as isize) })) + Some($output_id_type(unsafe { *$array.offset($i as isize) })) } }}; } +macro_rules! unsafe_tsk_column_access_and_map_into { + ($i: expr, $lo: expr, $hi: expr, $array: expr) => {{ + unsafe_tsk_column_access!($i, $lo, $hi, $array).map(|v| v.into()) + }}; +} + macro_rules! unsafe_tsk_ragged_column_access { ($i: expr, $lo: expr, $hi: expr, $array: expr, $offset_array: expr, $offset_array_len: expr) => {{ - let i = $crate::SizeType::try_from($i)?; + let i = $crate::SizeType::try_from($i).ok()?; if $i < $lo || i >= $hi { - Err(TskitError::IndexError {}) + None } else if $offset_array_len == 0 { - Ok(None) + None } else { let start = unsafe { *$offset_array.offset($i as isize) }; let stop = if i < $hi { @@ -59,23 +65,23 @@ macro_rules! unsafe_tsk_ragged_column_access { $offset_array_len as tsk_size_t }; if start == stop { - Ok(None) + None } else { let mut buffer = vec![]; for i in start..stop { buffer.push(unsafe { *$array.offset(i as isize) }); } - Ok(Some(buffer)) + Some(buffer) } } }}; ($i: expr, $lo: expr, $hi: expr, $array: expr, $offset_array: expr, $offset_array_len: expr, $output_id_type: ty) => {{ - let i = $crate::SizeType::try_from($i)?; + let i = $crate::SizeType::try_from($i).ok()?; if $i < $lo || i >= $hi { - Err(TskitError::IndexError {}) + None } else if $offset_array_len == 0 { - Ok(None) + None } else { let start = unsafe { *$offset_array.offset($i as isize) }; let stop = if i < $hi { @@ -84,14 +90,14 @@ macro_rules! unsafe_tsk_ragged_column_access { $offset_array_len as tsk_size_t }; if start == stop { - Ok(None) + None } else { - Ok(Some(unsafe { + Some(unsafe { std::slice::from_raw_parts( $array.offset(start as isize) as *const $output_id_type, stop as usize - start as usize, ) - })) + }) } } }}; diff --git a/src/edge_table.rs b/src/edge_table.rs index eb6902656..84f66d6bb 100644 --- a/src/edge_table.rs +++ b/src/edge_table.rs @@ -30,10 +30,10 @@ fn make_edge_table_row(table: &EdgeTable, pos: tsk_id_t) -> Option let table_ref = table.table_; Some(EdgeTableRow { id: pos.into(), - left: table.left(pos).ok()?, - right: table.right(pos).ok()?, - parent: table.parent(pos).ok()?, - child: table.child(pos).ok()?, + left: table.left(pos)?, + right: table.right(pos)?, + parent: table.parent(pos)?, + child: table.child(pos)?, metadata: table_row_decode_metadata!(table, table_ref, pos).map(|m| m.to_vec()), }) } @@ -83,48 +83,42 @@ impl<'a> EdgeTable<'a> { /// Return the ``parent`` value from row ``row`` of the table. /// - /// # Errors + /// # Returns /// - /// Will return [``IndexError``](crate::TskitError::IndexError) - /// if ``row`` is out of range. - pub fn parent + Copy>(&'a self, row: E) -> Result { + /// * `Some(parent)` if `u` is valid. + /// * `None` otherwise. + pub fn parent + Copy>(&'a self, row: E) -> Option { unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.parent, NodeId) } /// Return the ``child`` value from row ``row`` of the table. /// - /// # Errors + /// # Returns /// - /// Will return [``IndexError``](crate::TskitError::IndexError) - /// if ``row`` is out of range. - pub fn child + Copy>(&'a self, row: E) -> Result { + /// * `Some(child)` if `u` is valid. + /// * `None` otherwise. + pub fn child + Copy>(&'a self, row: E) -> Option { unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.child, NodeId) } /// Return the ``left`` value from row ``row`` of the table. /// - /// # Errors + /// # Returns /// - /// Will return [``IndexError``](crate::TskitError::IndexError) - /// if ``row`` is out of range. - pub fn left + Copy>(&'a self, row: E) -> Result { - match unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.left) { - Ok(p) => Ok(p.into()), - Err(e) => Err(e), - } + /// * `Some(position)` if `u` is valid. + /// * `None` otherwise. + pub fn left + Copy>(&'a self, row: E) -> Option { + unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.left, Position) } /// Return the ``right`` value from row ``row`` of the table. /// - /// # Errors + /// # Returns /// - /// Will return [``IndexError``](crate::TskitError::IndexError) - /// if ``row`` is out of range. - pub fn right + Copy>(&'a self, row: E) -> Result { - match unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.right) { - Ok(p) => Ok(p.into()), - Err(e) => Err(e), - } + /// * `Some(position)` if `u` is valid. + /// * `None` otherwise. + pub fn right + Copy>(&'a self, row: E) -> Option { + unsafe_tsk_column_access_and_map_into!(row.into().0, 0, self.num_rows(), self.table_.right) } pub fn metadata( diff --git a/src/individual_table.rs b/src/individual_table.rs index 06f6c6996..c5c40efa0 100644 --- a/src/individual_table.rs +++ b/src/individual_table.rs @@ -55,9 +55,9 @@ fn make_individual_table_row(table: &IndividualTable, pos: tsk_id_t) -> Option IndividualTable<'a> { /// Return the flags for a given row. /// - /// # Errors + /// # Returns /// - /// * [`TskitError::IndexError`] if `row` is out of range. - pub fn flags + Copy>( - &self, - row: I, - ) -> Result { - match unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.flags) { - Ok(f) => Ok(IndividualFlags::from(f)), - Err(e) => Err(e), - } + /// * `Some(flags)` if `row` is valid. + /// * `None` otherwise. + pub fn flags + Copy>(&self, row: I) -> Option { + unsafe_tsk_column_access_and_map_into!(row.into().0, 0, self.num_rows(), self.table_.flags) } /// Return the locations for a given row. /// - /// # Errors + /// # Returns /// - /// * [`TskitError::IndexError`] if `row` is out of range. - pub fn location + Copy>( - &self, - row: I, - ) -> Result, TskitError> { + /// * `Some(location)` if `row` is valid. + /// * `None` otherwise. + pub fn location + Copy>(&self, row: I) -> Option<&[Location]> { unsafe_tsk_ragged_column_access!( row.into().0, 0, @@ -136,13 +129,11 @@ impl<'a> IndividualTable<'a> { /// Return the parents for a given row. /// - /// # Errors + /// # Returns /// - /// * [`TskitError::IndexError`] if `row` is out of range. - pub fn parents + Copy>( - &self, - row: I, - ) -> Result, TskitError> { + /// * `Some(parents)` if `row` is valid. + /// * `None` otherwise. + pub fn parents + Copy>(&self, row: I) -> Option<&[IndividualId]> { unsafe_tsk_ragged_column_access!( row.into().0, 0, diff --git a/src/migration_table.rs b/src/migration_table.rs index 96aaa8ea2..62fecbcf7 100644 --- a/src/migration_table.rs +++ b/src/migration_table.rs @@ -36,12 +36,12 @@ fn make_migration_table_row(table: &MigrationTable, pos: tsk_id_t) -> Option MigrationTable<'a> { /// Return the left coordinate for a given row. /// - /// # Errors + /// # Returns /// - /// * [`TskitError::IndexError`] if `row` is out of range. - pub fn left + Copy>(&'a self, row: M) -> Result { - match unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.left) { - Ok(p) => Ok(p.into()), - Err(e) => Err(e), - } + /// * `Some(position)` if `row` is valid. + /// * `None` otherwise. + pub fn left + Copy>(&'a self, row: M) -> Option { + unsafe_tsk_column_access_and_map_into!(row.into().0, 0, self.num_rows(), self.table_.left) } /// Return the right coordinate for a given row. /// - /// # Errors + /// # Returns /// - /// * [`TskitError::IndexError`] if `row` is out of range. - pub fn right + Copy>(&'a self, row: M) -> Result { - match unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.right) { - Ok(p) => Ok(p.into()), - Err(e) => Err(e), - } + /// * `Some(positions)` if `row` is valid. + /// * `None` otherwise. + pub fn right + Copy>(&'a self, row: M) -> Option { + unsafe_tsk_column_access_and_map_into!(row.into().0, 0, self.num_rows(), self.table_.right) } /// Return the node for a given row. /// - /// # Errors + /// # Returns /// - /// * [`TskitError::IndexError`] if `row` is out of range. - pub fn node + Copy>(&'a self, row: M) -> Result { + /// * `Some(node)` if `row` is valid. + /// * `None` otherwise. + pub fn node + Copy>(&'a self, row: M) -> Option { unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.node, NodeId) } /// Return the source population for a given row. /// - /// # Errors + /// # Returns /// - /// * [`TskitError::IndexError`] if `row` is out of range. - pub fn source + Copy>( - &'a self, - row: M, - ) -> Result { + /// * `Some(population)` if `row` is valid. + /// * `None` otherwise. + pub fn source + Copy>(&'a self, row: M) -> Option { unsafe_tsk_column_access!( row.into().0, 0, @@ -143,10 +138,11 @@ impl<'a> MigrationTable<'a> { /// Return the destination population for a given row. /// - /// # Errors + /// # Returns /// - /// * [`TskitError::IndexError`] if `row` is out of range. - pub fn dest + Copy>(&'a self, row: M) -> Result { + /// * `Some(population)` if `row` is valid. + /// * `None` otherwise. + pub fn dest + Copy>(&'a self, row: M) -> Option { unsafe_tsk_column_access!( row.into().0, 0, @@ -158,21 +154,21 @@ impl<'a> MigrationTable<'a> { /// Return the time of the migration event for a given row. /// - /// # Errors + /// # Returns /// - /// * [`TskitError::IndexError`] if `row` is out of range. - pub fn time + Copy>(&'a self, row: M) -> Result { - match unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.time) { - Ok(t) => Ok(t.into()), - Err(e) => Err(e), - } + /// * `Some(time)` if `row` is valid. + /// * `None` otherwise. + pub fn time + Copy>(&'a self, row: M) -> Option