Skip to content

Commit 1b224ba

Browse files
committed
Improvements to handling of tsk_flags_t:
* Add RawFlags as typedef for tsk_flags_t * Add From<RawFlags> for flags types. The implementation will remove invalid bits that are set, except for NodeFlags/IndividualFlags which allow client-defined flags. * Flags types are now repr(transparent) * Functions taking flags are now generic over Into<flags type> Breaking changes: * Added NodeFlags and InidividualFlags as first-class types. Functions previously returning, e.g, &[tsk_flags_t] now return &[NodeFlags], etc.. Due to repr(transparent), these return values have the same ABI. Closes #226
1 parent 5f558cb commit 1b224ba

File tree

10 files changed

+277
-67
lines changed

10 files changed

+277
-67
lines changed

src/_macros.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,29 @@ macro_rules! impl_time_position_arithmetic {
498498
};
499499
}
500500

501+
macro_rules! impl_from_for_flag_types {
502+
($flagstype: ty) => {
503+
impl From<$crate::RawFlags> for $flagstype {
504+
fn from(value: $crate::RawFlags) -> Self {
505+
<$flagstype>::from_bits_truncate(value)
506+
}
507+
}
508+
};
509+
}
510+
511+
macro_rules! impl_flags {
512+
($flagstype: ty) => {
513+
impl $flagstype {
514+
/// We do not enforce valid flags in the library.
515+
/// This function will return `true` if any bits
516+
/// are set that do not correspond to allowed flags.
517+
pub fn is_valid(&self) -> bool {
518+
Self::from_bits(self.bits()).is_some()
519+
}
520+
}
521+
};
522+
}
523+
501524
/// Convenience macro to handle implementing
502525
/// [`crate::metadata::MetadataRoundtrip`]
503526
#[macro_export]

src/flags.rs

Lines changed: 98 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::bindings as ll_bindings;
2-
use crate::tsk_flags_t;
2+
use crate::RawFlags;
33
use bitflags::bitflags;
44

55
bitflags! {
@@ -39,7 +39,8 @@ bitflags! {
3939
/// assert!(!flags.contains(SO::FILTER_POPULATIONS));
4040
/// ```
4141
#[derive(Default)]
42-
pub struct SimplificationOptions: tsk_flags_t {
42+
#[repr(transparent)]
43+
pub struct SimplificationOptions: RawFlags {
4344
/// Default behavior
4445
const NONE = 0;
4546
const FILTER_SITES = ll_bindings::TSK_FILTER_SITES;
@@ -70,7 +71,8 @@ bitflags! {
7071
bitflags! {
7172
/// Modify behavior of [`crate::TableCollection::clear`].
7273
#[derive(Default)]
73-
pub struct TableClearOptions : tsk_flags_t {
74+
#[repr(transparent)]
75+
pub struct TableClearOptions : RawFlags {
7476
/// Default behavior.
7577
const NONE = 0;
7678
const CLEAR_METADATA_SCHEMAS = ll_bindings::TSK_CLEAR_METADATA_SCHEMAS;
@@ -82,7 +84,8 @@ bitflags! {
8284
bitflags! {
8385
/// Modify behavior of [`crate::TableCollection::equals`].
8486
#[derive(Default)]
85-
pub struct TableEqualityOptions : tsk_flags_t {
87+
#[repr(transparent)]
88+
pub struct TableEqualityOptions : RawFlags {
8689
/// Default behavior.
8790
const NONE = 0;
8891
const IGNORE_METADATA = ll_bindings::TSK_CMP_IGNORE_METADATA;
@@ -95,7 +98,8 @@ bitflags! {
9598
bitflags! {
9699
/// Modify behavior of [`crate::TableCollection::sort`].
97100
#[derive(Default)]
98-
pub struct TableSortOptions : tsk_flags_t {
101+
#[repr(transparent)]
102+
pub struct TableSortOptions : RawFlags {
99103
/// Default behavior.
100104
const NONE = 0;
101105
/// Do not validate contents of edge table.
@@ -106,7 +110,8 @@ bitflags! {
106110
bitflags! {
107111
/// Modify behavior of [`crate::TableCollection::sort_individuals`].
108112
#[derive(Default)]
109-
pub struct IndividualTableSortOptions : tsk_flags_t {
113+
#[repr(transparent)]
114+
pub struct IndividualTableSortOptions : RawFlags {
110115
/// Default behavior.
111116
const NONE = 0;
112117
}
@@ -116,7 +121,8 @@ bitflags! {
116121
/// Specify the behavior of iterating over [`Tree`] objects.
117122
/// See [`TreeSequence::tree_iterator`].
118123
#[derive(Default)]
119-
pub struct TreeFlags: tsk_flags_t {
124+
#[repr(transparent)]
125+
pub struct TreeFlags: RawFlags {
120126
/// Default behavior.
121127
const NONE = 0;
122128
/// Update sample lists, enabling [`Tree::samples`].
@@ -140,7 +146,8 @@ bitflags! {
140146
/// call [`crate::TableCollection::build_index`] prior to calling
141147
/// [`crate::TableCollection::dump`].
142148
#[derive(Default)]
143-
pub struct TableOutputOptions : tsk_flags_t {
149+
#[repr(transparent)]
150+
pub struct TableOutputOptions : RawFlags {
144151
const NONE = 0;
145152
}
146153
}
@@ -149,7 +156,8 @@ bitflags! {
149156
/// Modify behavior of [`crate::TableCollection::tree_sequence`]
150157
/// and [`crate::TreeSequence::new`].
151158
#[derive(Default)]
152-
pub struct TreeSequenceFlags: tsk_flags_t {
159+
#[repr(transparent)]
160+
pub struct TreeSequenceFlags: RawFlags {
153161
/// Default behavior
154162
const NONE = 0;
155163
/// If used, then build table indexes if they are not present.
@@ -159,9 +167,10 @@ bitflags! {
159167

160168
bitflags! {
161169
#[derive(Default)]
162-
pub struct TableIntegrityCheckFlags: tsk_flags_t {
170+
#[repr(transparent)]
171+
pub struct TableIntegrityCheckFlags: RawFlags {
163172
/// Default behavior is a set of basic checks
164-
const DEFAULT = 0;
173+
const NONE = 0;
165174
/// Check that edges are ordered
166175
const CHECK_EDGE_ORDERING =ll_bindings::TSK_CHECK_EDGE_ORDERING;
167176
/// Check that sites are ordered
@@ -180,3 +189,81 @@ bitflags! {
180189
const CHECK_TREES=ll_bindings::TSK_CHECK_TREES;
181190
}
182191
}
192+
193+
bitflags! {
194+
#[derive(Default)]
195+
#[repr(transparent)]
196+
/// Node flags
197+
pub struct NodeFlags : RawFlags {
198+
/// Default (empty)
199+
const NONE = 0;
200+
/// Node is a sample
201+
const IS_SAMPLE = ll_bindings::TSK_NODE_IS_SAMPLE;
202+
}
203+
}
204+
205+
bitflags! {
206+
#[derive(Default)]
207+
#[repr(transparent)]
208+
/// Individual flags
209+
pub struct IndividualFlags : RawFlags {
210+
/// Default (empty)
211+
const NONE = 0;
212+
}
213+
}
214+
215+
impl_flags!(SimplificationOptions);
216+
impl_flags!(TableClearOptions);
217+
impl_flags!(TableEqualityOptions);
218+
impl_flags!(TreeSequenceFlags);
219+
impl_flags!(TableSortOptions);
220+
impl_flags!(TreeFlags);
221+
impl_flags!(IndividualTableSortOptions);
222+
impl_flags!(TableIntegrityCheckFlags);
223+
impl_flags!(TableOutputOptions);
224+
225+
impl_from_for_flag_types!(SimplificationOptions);
226+
impl_from_for_flag_types!(TableClearOptions);
227+
impl_from_for_flag_types!(TableEqualityOptions);
228+
impl_from_for_flag_types!(TreeSequenceFlags);
229+
impl_from_for_flag_types!(TableSortOptions);
230+
impl_from_for_flag_types!(TreeFlags);
231+
impl_from_for_flag_types!(IndividualTableSortOptions);
232+
impl_from_for_flag_types!(TableIntegrityCheckFlags);
233+
impl_from_for_flag_types!(TableOutputOptions);
234+
235+
impl From<RawFlags> for NodeFlags {
236+
fn from(flags: RawFlags) -> Self {
237+
// Safety: node flags can contain user-defined values.
238+
// It is an error on the user's part to define flags
239+
// in the first 16 bits, as per the C API docs.
240+
unsafe { Self::from_bits_unchecked(flags) }
241+
}
242+
}
243+
244+
impl From<RawFlags> for IndividualFlags {
245+
fn from(flags: RawFlags) -> Self {
246+
// Safety: node flags can contain user-defined values.
247+
// It is an error on the user's part to define flags
248+
// in the first 16 bits, as per the C API docs.
249+
unsafe { Self::from_bits_unchecked(flags) }
250+
}
251+
}
252+
253+
impl NodeFlags {
254+
/// We do not enforce valid flags in the library.
255+
/// This function will return `true` if any bits
256+
/// are set that do not correspond to allowed flags.
257+
pub fn is_valid(&self) -> bool {
258+
true
259+
}
260+
}
261+
262+
impl IndividualFlags {
263+
/// We do not enforce valid flags in the library.
264+
/// This function will return `true` if any bits
265+
/// are set that do not correspond to allowed flags.
266+
pub fn is_valid(&self) -> bool {
267+
true
268+
}
269+
}

src/individual_table.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
use crate::bindings as ll_bindings;
22
use crate::metadata;
3+
use crate::IndividualFlags;
34
use crate::IndividualId;
45
use crate::Location;
5-
use crate::{tsk_flags_t, tsk_id_t, tsk_size_t, TskitError};
6+
use crate::{tsk_id_t, tsk_size_t, TskitError};
67

78
/// Row of a [`IndividualTable`]
89
pub struct IndividualTableRow {
910
pub id: IndividualId,
10-
pub flags: tsk_flags_t,
11+
pub flags: IndividualFlags,
1112
pub location: Option<Vec<Location>>,
1213
pub parents: Option<Vec<IndividualId>>,
1314
pub metadata: Option<Vec<u8>>,
@@ -110,8 +111,14 @@ impl<'a> IndividualTable<'a> {
110111
/// # Errors
111112
///
112113
/// * [`TskitError::IndexError`] if `row` is out of range.
113-
pub fn flags<I: Into<IndividualId> + Copy>(&self, row: I) -> Result<tsk_flags_t, TskitError> {
114-
unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.flags)
114+
pub fn flags<I: Into<IndividualId> + Copy>(
115+
&self,
116+
row: I,
117+
) -> Result<IndividualFlags, TskitError> {
118+
match unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.flags) {
119+
Ok(f) => Ok(IndividualFlags::from(f)),
120+
Err(e) => Err(e),
121+
}
115122
}
116123

117124
/// Return the locations for a given row.

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,9 @@ impl_id_traits!(ProvenanceId);
449449
/// the error message is stored for diplay.
450450
pub type TskReturnValue = Result<i32, TskitError>;
451451

452+
/// Alias for tsk_flags_t
453+
pub type RawFlags = crate::bindings::tsk_flags_t;
454+
452455
/// Version of the rust crate.
453456
///
454457
/// To get the C API version, see:

src/node_table.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
use crate::bindings as ll_bindings;
22
use crate::metadata;
3+
use crate::NodeFlags;
34
use crate::SizeType;
45
use crate::Time;
5-
use crate::{tsk_flags_t, tsk_id_t, TskitError};
6+
use crate::{tsk_id_t, TskitError};
67
use crate::{IndividualId, NodeId, PopulationId};
78

89
/// Row of a [`NodeTable`]
910
pub struct NodeTableRow {
1011
pub id: NodeId,
1112
pub time: Time,
12-
pub flags: tsk_flags_t,
13+
pub flags: NodeFlags,
1314
pub population: PopulationId,
1415
pub individual: IndividualId,
1516
pub metadata: Option<Vec<u8>>,
@@ -106,15 +107,18 @@ impl<'a> NodeTable<'a> {
106107
///
107108
/// Will return [``IndexError``](crate::TskitError::IndexError)
108109
/// if ``row`` is out of range.
109-
pub fn flags<N: Into<NodeId> + Copy>(&'a self, row: N) -> Result<tsk_flags_t, TskitError> {
110-
unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.flags)
110+
pub fn flags<N: Into<NodeId> + Copy>(&'a self, row: N) -> Result<NodeFlags, TskitError> {
111+
match unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.flags) {
112+
Ok(f) => Ok(NodeFlags::from(f)),
113+
Err(e) => Err(e),
114+
}
111115
}
112116

113117
/// Mutable access to node flags.
114-
pub fn flags_array_mut(&mut self) -> &mut [tsk_flags_t] {
118+
pub fn flags_array_mut(&mut self) -> &mut [NodeFlags] {
115119
unsafe {
116120
std::slice::from_raw_parts_mut(
117-
self.table_.flags,
121+
self.table_.flags.cast::<NodeFlags>(),
118122
crate::util::handle_u64_to_usize(self.table_.num_rows),
119123
)
120124
}
@@ -215,7 +219,7 @@ impl<'a> NodeTable<'a> {
215219
pub fn samples_as_vector(&self) -> Vec<NodeId> {
216220
let mut samples: Vec<NodeId> = vec![];
217221
for row in self.iter() {
218-
if row.flags & crate::TSK_NODE_IS_SAMPLE > 0 {
222+
if row.flags.contains(NodeFlags::IS_SAMPLE) {
219223
samples.push(row.id);
220224
}
221225
}

src/prelude.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ pub use streaming_iterator::DoubleEndedStreamingIterator;
99
pub use streaming_iterator::StreamingIterator;
1010
pub use {
1111
crate::EdgeId, crate::IndividualId, crate::Location, crate::MigrationId, crate::MutationId,
12-
crate::NodeId, crate::PopulationId, crate::Position, crate::SiteId, crate::SizeType,
13-
crate::Time,
12+
crate::NodeId, crate::PopulationId, crate::Position, crate::RawFlags, crate::SiteId,
13+
crate::SizeType, crate::Time,
1414
};

0 commit comments

Comments
 (0)