From a7df84eb3653b9b518441dc031919be58c55cf20 Mon Sep 17 00:00:00 2001 From: Daniel Danis Date: Fri, 22 May 2026 18:38:55 +0200 Subject: [PATCH 1/5] Next development iteration `0.7.4-dev0`. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index fb0a1c2..d41fcb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ontolius" -version = "0.7.3" +version = "0.7.4-dev0" description = "A fast and safe crate for working with biomedical ontologies." keywords = ["ontology", "bioinformatics", "HPO", "MAxO", "GO"] edition = "2021" From d2c241c95760d9311dc67579197666f0324d1034 Mon Sep 17 00:00:00 2001 From: Daniel Danis Date: Fri, 22 May 2026 20:49:53 +0200 Subject: [PATCH 2/5] Improve trait ergonomics. --- .zed/settings.json | 11 +++ src/ontology/api.rs | 4 ++ src/ontology/csr/beta.rs | 141 +++++++++++++++++++++++++++++++++++++++ src/term.rs | 31 +++++++++ tests/test_ontology.rs | 28 ++++++++ 5 files changed, 215 insertions(+) create mode 100644 .zed/settings.json create mode 100644 tests/test_ontology.rs diff --git a/.zed/settings.json b/.zed/settings.json new file mode 100644 index 0000000..a73c01c --- /dev/null +++ b/.zed/settings.json @@ -0,0 +1,11 @@ +{ + "lsp": { + "rust-analyzer": { + "initialization_options": { + "cargo": { + "features": "all", + }, + }, + }, + }, +} diff --git a/src/ontology/api.rs b/src/ontology/api.rs index 7ad68f1..7668830 100644 --- a/src/ontology/api.rs +++ b/src/ontology/api.rs @@ -125,6 +125,8 @@ where } /// Traversals in the ontology index space. +/// +/// The child-parent relationship is established solely via the `is_a` relationship. pub trait HierarchyTraversals { /// Get the index of the `query` term or `None` if the term is unknown. fn term_index(&self, query: &Q) -> Option @@ -208,6 +210,8 @@ pub trait HierarchyWalks { } /// Tests if an ontology term is a parent, a child, an ancestor, or descendant of another term. +/// +/// The child-parent relationship is established solely via the `is_a` relationship. pub trait HierarchyQueries { /// Test if `sub` is child of `obj`. /// diff --git a/src/ontology/csr/beta.rs b/src/ontology/csr/beta.rs index 6e26b3b..db51241 100644 --- a/src/ontology/csr/beta.rs +++ b/src/ontology/csr/beta.rs @@ -115,6 +115,31 @@ where } } +macro_rules! impl_ontology_terms { + ($t:ty) => { + impl OntologyTerms for $t + where + I: Idx, + { + fn iter_terms<'a>(&'a self) -> impl Iterator + where + T: 'a, + { + (**self).iter_terms() + } + + fn term_by_id(&self, id: &ID) -> Option<&T> + where + ID: Identified, + { + (**self).term_by_id(id) + } + } + }; +} +impl_ontology_terms!(&CsrOntology); +impl_ontology_terms!(Box>); + impl HierarchyTraversals for CsrOntology where I: Idx + Hash, @@ -150,6 +175,39 @@ where } } } +macro_rules! impl_hierarchy_traversal { + ($t:ty) => { + impl HierarchyTraversals for $t + where + I: Idx + Hash, + { + fn term_index(&self, query: &Q) -> Option + where + Q: Identified, + { + (**self).term_index(query) + } + + fn iter_child_idxs(&self, query: I) -> impl Iterator { + (**self).iter_child_idxs(query) + } + + fn iter_descendant_idxs(&self, query: I) -> impl Iterator { + (**self).iter_descendant_idxs(query) + } + + fn iter_parent_idxs(&self, query: I) -> impl Iterator { + (**self).iter_descendant_idxs(query) + } + + fn iter_ancestor_idxs(&self, query: I) -> impl Iterator { + (**self).iter_ancestor_idxs(query) + } + } + }; +} +impl_hierarchy_traversal!(&CsrOntology); +impl_hierarchy_traversal!(Box>); impl HierarchyWalks for CsrOntology where @@ -213,6 +271,46 @@ where } } +macro_rules! impl_hierarchy_walks { + ($t:ty) => { + impl HierarchyWalks for $t + where + I: Idx + Hash, + T: Identified, + { + fn iter_parent_ids<'a, ID>(&'a self, query: &ID) -> impl Iterator + where + ID: Identified, + { + (**self).iter_parent_ids(query) + } + + fn iter_child_ids<'a, ID>(&'a self, query: &ID) -> impl Iterator + where + ID: Identified, + { + (**self).iter_child_ids(query) + } + + fn iter_ancestor_ids<'a, ID>(&'a self, query: &ID) -> impl Iterator + where + ID: Identified, + { + (**self).iter_ancestor_ids(query) + } + + fn iter_descendant_ids<'a, ID>(&'a self, query: &ID) -> impl Iterator + where + ID: Identified, + { + (**self).iter_descendant_ids(query) + } + } + }; +} +impl_hierarchy_walks!(&CsrOntology); +impl_hierarchy_walks!(Box>); + impl HierarchyQueries for CsrOntology where I: Idx + Hash, @@ -274,6 +372,49 @@ where } } +macro_rules! impl_hierarchy_queries { + ($t:ty) => { + impl HierarchyQueries for $t + where + I: Idx + Hash, + { + fn is_child_of(&self, sub: &S, obj: &O) -> bool + where + S: Identified, + O: Identified, + { + (**self).is_child_of(sub, obj) + } + + fn is_descendant_of(&self, sub: &S, obj: &O) -> bool + where + S: Identified, + O: Identified, + { + (**self).is_descendant_of(sub, obj) + } + + fn is_parent_of(&self, sub: &S, obj: &O) -> bool + where + S: Identified, + O: Identified, + { + (**self).is_parent_of(sub, obj) + } + + fn is_ancestor_of(&self, sub: &S, obj: &O) -> bool + where + S: Identified, + O: Identified, + { + (**self).is_ancestor_of(sub, obj) + } + } + }; +} +impl_hierarchy_queries!(&CsrOntology); +impl_hierarchy_queries!(Box>); + impl MetadataAware for CsrOntology where I: Idx, diff --git a/src/term.rs b/src/term.rs index a7b3ffa..4bb41db 100644 --- a/src/term.rs +++ b/src/term.rs @@ -135,6 +135,12 @@ pub mod simple { } } + impl Identified for &SimpleMinimalTerm { + fn identifier(&self) -> &TermId { + (**self).identifier() + } + } + impl AltTermIdAware for SimpleMinimalTerm { type TermIdIter<'a> = std::slice::Iter<'a, TermId> @@ -150,6 +156,21 @@ pub mod simple { } } + impl AltTermIdAware for &SimpleMinimalTerm { + type TermIdIter<'a> + = std::slice::Iter<'a, TermId> + where + Self: 'a; + + fn iter_alt_term_ids(&self) -> Self::TermIdIter<'_> { + (**self).iter_alt_term_ids() + } + + fn alt_term_id_count(&self) -> usize { + (**self).alt_term_id_count() + } + } + impl MinimalTerm for SimpleMinimalTerm { fn name(&self) -> &str { self.name.as_str() @@ -160,6 +181,16 @@ pub mod simple { } } + impl MinimalTerm for &SimpleMinimalTerm { + fn name(&self) -> &str { + (**self).name() + } + + fn is_current(&self) -> bool { + (**self).is_current() + } + } + #[derive(Debug, PartialEq, Eq, Clone)] pub struct SimpleTerm { term_id: TermId, diff --git a/tests/test_ontology.rs b/tests/test_ontology.rs new file mode 100644 index 0000000..6e20d1d --- /dev/null +++ b/tests/test_ontology.rs @@ -0,0 +1,28 @@ +mod csr { + + use ontolius::ontology::{ + csr::MinimalCsrOntology, HierarchyQueries, HierarchyTraversals, HierarchyWalks, + OntologyTerms, + }; + + #[test] + fn test_csr_ontology_can_be_used_with_trait_bounds() { + let o: Option = None; + + if o.is_some() { + // This will never run. It does not matter, + // since it is enough that the code compiles. + let o: &MinimalCsrOntology = o.as_ref().unwrap(); + + pretend_to_use_hierarchy_queries(o); + pretend_to_use_hierarchy_walks(o); + pretend_to_use_hierarchy_traversals(o); + pretend_to_use_ontology_terms(o); + } + + fn pretend_to_use_hierarchy_queries(_o: impl HierarchyQueries) {} + fn pretend_to_use_hierarchy_walks(_o: impl HierarchyWalks) {} + fn pretend_to_use_hierarchy_traversals(_o: impl HierarchyTraversals) {} + fn pretend_to_use_ontology_terms(_o: impl OntologyTerms) {} + } +} From 90d13db527ccbcaaeabff4d6800145cc94b465d9 Mon Sep 17 00:00:00 2001 From: Daniel Danis Date: Fri, 22 May 2026 20:51:55 +0200 Subject: [PATCH 3/5] Update .gitignore. --- .gitignore | 1 + .zed/settings.json | 11 ----------- 2 files changed, 1 insertion(+), 11 deletions(-) delete mode 100644 .zed/settings.json diff --git a/.gitignore b/.gitignore index a2e6921..03bbf06 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ Cargo.lock # IDE files .vscode/ .idea/ +.zed/ # Perf data perf.data* diff --git a/.zed/settings.json b/.zed/settings.json deleted file mode 100644 index a73c01c..0000000 --- a/.zed/settings.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "lsp": { - "rust-analyzer": { - "initialization_options": { - "cargo": { - "features": "all", - }, - }, - }, - }, -} From 1dfaa90c4bc8135997cac57796a20a9b162b9cc9 Mon Sep 17 00:00:00 2001 From: Daniel Danis Date: Fri, 22 May 2026 20:56:36 +0200 Subject: [PATCH 4/5] Update ci.yml --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c139ee3..1e0ba8a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: toolchain: ${{ matrix.toolchain }} - name: Run tests - run: cargo test --release + run: cargo test run-all-features: runs-on: ubuntu-latest @@ -37,7 +37,7 @@ jobs: toolchain: "stable" - name: Run tests - run: cargo test --features serde,pyo3 --release + run: cargo test --features serde,pyo3 format: runs-on: ubuntu-latest From 6d361017e0ba635afb4535a65c23c37d2bcaf826 Mon Sep 17 00:00:00 2001 From: Daniel Danis Date: Wed, 27 May 2026 09:34:26 +0200 Subject: [PATCH 5/5] Make release `0.7.4`. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d41fcb9..b68f6b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ontolius" -version = "0.7.4-dev0" +version = "0.7.4" description = "A fast and safe crate for working with biomedical ontologies." keywords = ["ontology", "bioinformatics", "HPO", "MAxO", "GO"] edition = "2021"