Skip to content

Add another experimental trait idea for metadata. #261

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 16, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions tests/experimental.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,79 @@ mod experimental_features {

use tskit::TableAccess;

// Goal: proc macro this up
// Design notes for future:
// * We can probably drop this trait.
// * We want a derive macro based on XMetadataRetrieval,
// where X is a table type.
// * So hopefully we can start there.
trait MetadataRetrieval<R> {
type Metadata: tskit::metadata::MetadataRoundtrip;
fn metadata(&self, r: impl Into<R>) -> Result<Option<Self::Metadata>, tskit::TskitError>;
}

// Specific traits cover the various row id types
trait MutationMetadataRetrieval: MetadataRetrieval<tskit::MutationId> {
fn mutation_metadata(
&self,
row: impl Into<tskit::MutationId>,
) -> Result<
Option<<Self as MetadataRetrieval<tskit::MutationId>>::Metadata>,
tskit::TskitError,
>
where
<Self as MetadataRetrieval<tskit::MutationId>>::Metadata:
tskit::metadata::MutationMetadata;
}

// Blanket implementations are possible given the above
// two defnitions, putting all boiler plate out of sight!
impl<T> MutationMetadataRetrieval for T
where
T: MetadataRetrieval<tskit::MutationId>,
<Self as MetadataRetrieval<tskit::MutationId>>::Metadata: tskit::metadata::MutationMetadata,
{
fn mutation_metadata(
&self,
row: impl Into<tskit::MutationId>,
) -> Result<
Option<<Self as MetadataRetrieval<tskit::MutationId>>::Metadata>,
tskit::TskitError,
> {
self.metadata(row)
}
}

trait IndividualMetadataRetrieval: MetadataRetrieval<tskit::IndividualId> {
fn individual_metadata(
&self,
row: impl Into<tskit::IndividualId>,
) -> Result<
Option<<Self as MetadataRetrieval<tskit::IndividualId>>::Metadata>,
tskit::TskitError,
>
where
<Self as MetadataRetrieval<tskit::IndividualId>>::Metadata:
tskit::metadata::MutationMetadata;
}

impl<T> IndividualMetadataRetrieval for T
where
T: MetadataRetrieval<tskit::IndividualId>,
<Self as MetadataRetrieval<tskit::IndividualId>>::Metadata:
tskit::metadata::IndividualMetadata,
{
fn individual_metadata(
&self,
row: impl Into<tskit::IndividualId>,
) -> Result<
Option<<Self as MetadataRetrieval<tskit::IndividualId>>::Metadata>,
tskit::TskitError,
> {
self.metadata(row)
}
}

// Name is not great.
// We'd like to have this be : tskit::TableAccess,
// but that's a big ask at this stage.
Expand All @@ -22,6 +95,13 @@ mod experimental_features {
effect_size: f64,
}

#[derive(serde::Serialize, serde::Deserialize, tskit::metadata::IndividualMetadata)]
#[serializer("serde_json")]
struct IndividualMetadataType {
fitness: f64,
location: [f64; 3],
}

// Goal:
//
// A table newtype can let us define tables in terms
Expand Down Expand Up @@ -57,6 +137,28 @@ mod experimental_features {
}
}

impl MetadataRetrieval<tskit::MutationId> for MyTableCollection {
type Metadata = MutationMetadataType;
fn metadata(
&self,
row: impl Into<tskit::MutationId>,
) -> Result<Option<MutationMetadataType>, tskit::TskitError> {
self.mutations()
.metadata::<MutationMetadataType>(row.into())
}
}

impl MetadataRetrieval<tskit::IndividualId> for MyTableCollection {
type Metadata = IndividualMetadataType;
fn metadata(
&self,
row: impl Into<tskit::IndividualId>,
) -> Result<Option<IndividualMetadataType>, tskit::TskitError> {
self.individuals()
.metadata::<IndividualMetadataType>(row.into())
}
}

#[test]
fn test_table_collection_newtype() {
let mut tables = MyTableCollection(tskit::TableCollection::new(1.0).unwrap());
Expand All @@ -67,6 +169,23 @@ mod experimental_features {
let decoded = tables.get_mutation_metadata(0).unwrap().unwrap();
assert_eq!(decoded.effect_size, 0.10);

// More ergonomic here...
// NOTE: this can no longer compile b/c we've
// got the pattern in place for > 1 trait.
// let decoded = tables.metadata(0).unwrap().unwrap();
// assert_eq!(decoded.effect_size, 0.10);

// ...but not here, which is how it would normally be called...
let decoded =
<MyTableCollection as MetadataRetrieval<tskit::MutationId>>::metadata(&tables, 0)
.unwrap()
.unwrap();
assert_eq!(decoded.effect_size, 0.10);

// ... but blanket impl may be a path to glory.
let decoded = tables.mutation_metadata(0).unwrap().unwrap();
assert_eq!(decoded.effect_size, 0.10);

// current API requires
let decoded = tables
.mutations()
Expand Down