Skip to content

Add support for table metadata schema #339

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

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -58,3 +58,7 @@ name = "tree_traversals"

[[example]]
name = "forward_simulation"

[[example]]
name = "metadata_schema"
required-features = ["derive"]
29 changes: 29 additions & 0 deletions examples/metadata_schema.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use tskit::prelude::*;
use tskit::TableCollection;

#[derive(serde::Serialize, serde::Deserialize, tskit::metadata::PopulationMetadata)]
#[serializer("serde_json")]
struct PopulationMetadata {
name: String,
}

fn main() {
let from_fp11 = r#"
{
"codec": "json",
"type": "object",
"name": "Population metadata",
"properties": {"name": {"type": "string"}}
}"#;

let mut tables = TableCollection::new(10.0).unwrap();
tables
.add_population_with_metadata(&PopulationMetadata {
name: "YRB".to_string(),
})
.unwrap();
tables
.set_json_metadata_schema_from_str(tskit::MetadataSchema::Populations, from_fp11)
.unwrap();
tables.dump("testit.trees", 0).unwrap();
}
7 changes: 7 additions & 0 deletions python_scripts/read_tablesfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import tskit
import sys

for f in sys.argv[1:]:
tables = tskit.TableCollection.load(f)
for pop in tables.populations:
print(pop)
1 change: 1 addition & 0 deletions python_scripts/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tskit = "0.5.1"
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -435,7 +435,7 @@ pub use mutation_table::{MutationTable, MutationTableRow, OwnedMutationTable};
pub use node_table::{NodeTable, NodeTableRow, OwnedNodeTable};
pub use population_table::{OwnedPopulationTable, PopulationTable, PopulationTableRow};
pub use site_table::{OwnedSiteTable, SiteTable, SiteTableRow};
pub use table_collection::TableCollection;
pub use table_collection::{MetadataSchema, TableCollection};
pub use traits::IndividualLocation;
pub use traits::IndividualParents;
pub use traits::NodeListGenerator;
83 changes: 83 additions & 0 deletions src/table_collection.rs
Original file line number Diff line number Diff line change
@@ -24,9 +24,23 @@ use crate::TskReturnValue;
use crate::TskitTypeAccess;
use crate::{tsk_id_t, tsk_size_t};
use crate::{EdgeId, NodeId};
use libc::{c_char, strlen};
use ll_bindings::tsk_table_collection_free;
use mbox::MBox;

pub enum MetadataSchema {
Toplevel,
Edges,
Nodes,
Sites,
Mutations,
Individuals,
Populations,
Migrations,
#[cfg(feature = "provenance")]
Provenance,
}

/// A table collection.
///
/// This is a thin wrapper around the C type
@@ -1202,6 +1216,35 @@ impl TableCollection {
};
handle_tsk_return_value!(rv)
}

/// Set a metadata schema
///
/// # Examples
///
pub fn set_json_metadata_schema_from_str(
&mut self,
level: MetadataSchema,
schema: impl AsRef<str>,
) -> TskReturnValue {
println!("{} {}", schema.as_ref(), schema.as_ref().len());
let cstr = std::ffi::CString::new(schema.as_ref()).unwrap();
println!("{:?}", cstr);
let len = unsafe { strlen(cstr.as_bytes_with_nul().as_ptr() as *const c_char) };
println!("{:?}", cstr);
println!("{}", len);
let rv = match level {
MetadataSchema::Populations => unsafe {
ll_bindings::tsk_population_table_set_metadata_schema(
&mut (*self.inner).populations,
cstr.as_bytes_with_nul().as_ptr() as *const c_char,
len.try_into().unwrap(),
)
},
_ => unimplemented!("haven't done it yet"),
};
println!("rv = {}", rv);
handle_tsk_return_value!(rv)
}
}

impl TableAccess for TableCollection {
@@ -2296,3 +2339,43 @@ mod test_adding_migrations {
}
}
}

#[cfg(test)]
mod test_metadata_schema {
use super::*;

#[test]
fn population_metadata_schema() {
let json_schema3 = r#"{"codec":"json","type":"object","name":"Population metadata","properties:"{"name":{"type":"string"}}}"#;
let json_schema3 = r#"{"codec":"json","type":"object","name":"Population metadata","properties":{"name":{"type":"string"}}}"#;
let json_schema2 = r#"{"codec":"json","name":"Population metadata","properties":{"name":{"type":"string"}},"type":"object"}"#;
let json_schema = r#"{"codec":"json","name":"Population metadata","properties":{"name":{"type":"string"}},"type":"object"}"#;

// YOU CANNOT HAVE A TRAILING COMMA AT THE END!!!!!!
let from_fp11 = r#"
{
"codec": "json",
"type": "object",
"name": "Population metadata",
"properties": {"name": {"type": "string"}}
}"#;

assert_eq!(json_schema, json_schema2);
let mut tables = TableCollection::new(10.).unwrap();
assert!(tables
.set_json_metadata_schema_from_str(MetadataSchema::Populations, from_fp11)
.is_ok());
assert!(!unsafe { (*tables.as_ptr()).populations.metadata_schema.is_null() });
let len = unsafe { (*tables.as_ptr()).populations.metadata_schema_length };
assert!(len > 0, "{}", len);
let schema =
unsafe { std::ffi::CStr::from_ptr((*tables.as_ptr()).populations.metadata_schema) };
assert_eq!(schema.to_str().unwrap(), from_fp11);
tables.dump("foo.trees", 0).unwrap();

//let tables = TableCollection::new_from_file("bananas.tables").unwrap();
//let schema =
// unsafe { std::ffi::CStr::from_ptr((*tables.as_ptr()).populations.metadata_schema) };
//println!("from tskit = {}", schema.to_str().unwrap());
}
}