From 6006dec1608a9415408fb677fc0fbebdb76e951c Mon Sep 17 00:00:00 2001 From: Manuel Holtgrewe Date: Wed, 15 Feb 2023 13:05:12 +0100 Subject: [PATCH 01/10] feat: implement Display for HgvsVariant and related types (#4) --- src/parser/display.rs | 843 ++++++++++++++++++++++++++++++++++++++++++ src/parser/mod.rs | 13 +- tests/data/reject | 4 + 3 files changed, 854 insertions(+), 6 deletions(-) create mode 100644 src/parser/display.rs diff --git a/src/parser/display.rs b/src/parser/display.rs new file mode 100644 index 0000000..69b6ee7 --- /dev/null +++ b/src/parser/display.rs @@ -0,0 +1,843 @@ +//! Implementation of Display trait. + +use std::fmt::Display; + +use crate::parser::ds::*; + +impl Display for Mu +where + T: Display, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Mu::Certain(value) => write!(f, "{}", value), + Mu::Uncertain(value) => write!(f, "({})", value), + } + } +} + +impl Display for GeneSymbol { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.value) + } +} + +impl Display for NaEdit { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + NaEdit::RefAlt { + reference, + alternative, + } => match (reference.len(), alternative.len()) { + (0, 0) => write!(f, "="), + (1, 1) => write!(f, "{}>{}", reference, alternative), + (0, _) => write!(f, "ins{}", alternative), + (_, 0) => write!(f, "del{}", reference), + (_, _) => write!(f, "del{}ins{}", reference, alternative), + }, + NaEdit::NumAlt { count, alternative } => match (count, alternative.len()) { + (0, 0) => write!(f, "="), + (0, _) => write!(f, "ins{}", alternative), + (_, 0) => write!(f, "del{}", count), + (_, _) => write!(f, "del{}ins{}", count, alternative), + }, + NaEdit::Del { reference } => write!(f, "del{}", reference), + NaEdit::Ins { alternative } => write!(f, "ins{}", alternative), + NaEdit::Dup { reference } => write!(f, "dup{}", reference), + NaEdit::InvRef { reference } => write!(f, "inv{}", reference), + NaEdit::InvNum { count } => write!(f, "inv{}", count), + } + } +} + +impl Display for UncertainLengthChange { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + UncertainLengthChange::None => write!(f, ""), + UncertainLengthChange::Unknown => write!(f, "?"), + UncertainLengthChange::Known(count) => write!(f, "{}", count), + } + } +} + +impl Display for Accession { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.value) + } +} + +impl Display for ProteinEdit { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ProteinEdit::Fs { + alternative, + terminal, + length, + } => match (alternative, terminal, length) { + (None, None, UncertainLengthChange::None) => write!(f, "fs"), + (None, None, UncertainLengthChange::Unknown) => write!(f, "fs?"), + (None, None, UncertainLengthChange::Known(count)) => write!(f, "fs{}", count), + (Some(alt), None, UncertainLengthChange::None) => write!(f, "{}fs", alt), + (Some(alt), None, UncertainLengthChange::Unknown) => write!(f, "{}fs?", alt), + (Some(alt), None, UncertainLengthChange::Known(count)) => { + write!(f, "{}fs{}", alt, count) + } + (None, Some(ter), UncertainLengthChange::None) => write!(f, "fs{}", ter), + (None, Some(ter), UncertainLengthChange::Unknown) => write!(f, "fs{}?", ter), + (None, Some(ter), UncertainLengthChange::Known(count)) => { + write!(f, "fs{}{}", ter, count) + } + (Some(alt), Some(ter), UncertainLengthChange::None) => { + write!(f, "{}fs{}", alt, ter) + } + (Some(alt), Some(ter), UncertainLengthChange::Unknown) => { + write!(f, "{}fs{}?", alt, ter) + } + (Some(alt), Some(ter), UncertainLengthChange::Known(count)) => { + write!(f, "{}fs{}{}", alt, ter, count) + } + }, + ProteinEdit::Ext { + aa_ext, + ext_aa, + change, + } => match (aa_ext, ext_aa, change) { + (None, None, UncertainLengthChange::None) => write!(f, "ext"), + (None, None, UncertainLengthChange::Unknown) => write!(f, "ext?"), + (None, None, UncertainLengthChange::Known(count)) => write!(f, "ext{}", count), + (Some(alt), None, UncertainLengthChange::None) => write!(f, "{}ext", alt), + (Some(alt), None, UncertainLengthChange::Unknown) => write!(f, "{}ext?", alt), + (Some(alt), None, UncertainLengthChange::Known(count)) => { + write!(f, "{}ext{}", alt, count) + } + (None, Some(ter), UncertainLengthChange::None) => write!(f, "ext{}", ter), + (None, Some(ter), UncertainLengthChange::Unknown) => write!(f, "ext{}?", ter), + (None, Some(ter), UncertainLengthChange::Known(count)) => { + write!(f, "ext{}{}", ter, count) + } + (Some(alt), Some(ter), UncertainLengthChange::None) => { + write!(f, "{}ext{}", alt, ter) + } + (Some(alt), Some(ter), UncertainLengthChange::Unknown) => { + write!(f, "{}ext{}?", alt, ter) + } + (Some(alt), Some(ter), UncertainLengthChange::Known(count)) => { + write!(f, "{}ext{}{}", alt, ter, count) + } + }, + ProteinEdit::Subst { alternative } => write!(f, "{}", alternative), + ProteinEdit::DelIns { alternative } => write!(f, "delins{}", alternative), + ProteinEdit::Ins { alternative } => write!(f, "ins{}", alternative), + ProteinEdit::Del => write!(f, "del"), + ProteinEdit::Dup => write!(f, "dup"), + ProteinEdit::Ident => write!(f, "="), + } + } +} + +impl Display for CdsLocEdit { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}{}", self.loc, self.edit) + } +} + +impl Display for CdsInterval { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}_{}", self.begin, self.end) + } +} + +impl Display for CdsPos { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.cds_from == CdsFrom::End { + write!(f, "*")?; + } + + write!(f, "{}", self.base)?; + + if let Some(offset) = self.offset { + if offset > 0 { + write!(f, "+")?; + } + write!(f, "{}", offset)?; + } + + Ok(()) + } +} + +#[cfg(test)] +mod test { + use pretty_assertions::assert_eq; + + use crate::parser::{ + Accession, CdsFrom, CdsInterval, CdsLocEdit, CdsPos, GeneSymbol, Mu, NaEdit, ProteinEdit, + UncertainLengthChange, + }; + + #[test] + fn mu() { + assert_eq!(format!("{}", Mu::Certain(42)), "42".to_string()); + assert_eq!(format!("{}", Mu::Uncertain(42)), "(42)".to_string()); + } + + #[test] + fn gene_symbol() { + assert_eq!( + format!( + "{}", + GeneSymbol { + value: "TTN".to_string() + } + ), + "TTN".to_string() + ); + } + + #[test] + fn na_edit_ref_alt() { + assert_eq!( + format!( + "{}", + NaEdit::RefAlt { + reference: "".to_string(), + alternative: "".to_string() + } + ), + "=".to_string() + ); + + assert_eq!( + format!( + "{}", + NaEdit::RefAlt { + reference: "C".to_string(), + alternative: "T".to_string() + } + ), + "C>T".to_string() + ); + + assert_eq!( + format!( + "{}", + NaEdit::RefAlt { + reference: "CC".to_string(), + alternative: "T".to_string() + } + ), + "delCCinsT".to_string() + ); + + assert_eq!( + format!( + "{}", + NaEdit::RefAlt { + reference: "C".to_string(), + alternative: "".to_string() + } + ), + "delC".to_string() + ); + + assert_eq!( + format!( + "{}", + NaEdit::RefAlt { + reference: "".to_string(), + alternative: "C".to_string() + } + ), + "insC".to_string() + ); + } + + #[test] + fn na_edit_num_alt() { + assert_eq!( + format!( + "{}", + NaEdit::NumAlt { + count: 0, + alternative: "".to_string() + } + ), + "=".to_string() + ); + + assert_eq!( + format!( + "{}", + NaEdit::NumAlt { + count: 0, + alternative: "T".to_string() + } + ), + "insT".to_string() + ); + assert_eq!( + format!( + "{}", + NaEdit::NumAlt { + count: 3, + alternative: "".to_string() + } + ), + "del3".to_string() + ); + + assert_eq!( + format!( + "{}", + NaEdit::NumAlt { + count: 3, + alternative: "T".to_string() + } + ), + "del3insT".to_string() + ); + } + + #[test] + fn na_edit_del() { + assert_eq!( + format!( + "{}", + NaEdit::Del { + reference: "T".to_string() + } + ), + "delT".to_string() + ); + } + + #[test] + fn na_edit_ins() { + assert_eq!( + format!( + "{}", + NaEdit::Ins { + alternative: "T".to_string() + } + ), + "insT".to_string() + ); + } + + #[test] + fn na_edit_dup() { + assert_eq!( + format!( + "{}", + NaEdit::Dup { + reference: "T".to_string() + } + ), + "dupT".to_string() + ); + } + + #[test] + fn na_edit_inv_ref() { + assert_eq!( + format!( + "{}", + NaEdit::InvRef { + reference: "T".to_string() + } + ), + "invT".to_string() + ); + } + + #[test] + fn na_edit_inv_num() { + assert_eq!( + format!("{}", NaEdit::InvNum { count: 3 }), + "inv3".to_string() + ); + } + + #[test] + fn uncertain_length_change() { + assert_eq!(format!("{}", UncertainLengthChange::None), "".to_string(),); + assert_eq!( + format!("{}", UncertainLengthChange::Unknown), + "?".to_string(), + ); + assert_eq!( + format!("{}", UncertainLengthChange::Known(42)), + "42".to_string(), + ); + } + + #[test] + fn accession() { + assert_eq!( + format!( + "{}", + Accession { + value: "TTN".to_string() + } + ), + "TTN".to_string() + ) + } + + #[test] + fn protein_edit_fs() { + assert_eq!( + format!( + "{}", + ProteinEdit::Fs { + alternative: None, + terminal: None, + length: UncertainLengthChange::None, + } + ), + "fs".to_string(), + ); + assert_eq!( + format!( + "{}", + ProteinEdit::Fs { + alternative: None, + terminal: None, + length: UncertainLengthChange::Unknown, + } + ), + "fs?".to_string(), + ); + assert_eq!( + format!( + "{}", + ProteinEdit::Fs { + alternative: None, + terminal: None, + length: UncertainLengthChange::Known(42), + } + ), + "fs42".to_string(), + ); + + assert_eq!( + format!( + "{}", + ProteinEdit::Fs { + alternative: Some("Leu".to_string()), + terminal: None, + length: UncertainLengthChange::None, + } + ), + "Leufs".to_string(), + ); + assert_eq!( + format!( + "{}", + ProteinEdit::Fs { + alternative: Some("Leu".to_string()), + terminal: None, + length: UncertainLengthChange::Unknown, + } + ), + "Leufs?".to_string(), + ); + assert_eq!( + format!( + "{}", + ProteinEdit::Fs { + alternative: Some("Leu".to_string()), + terminal: None, + length: UncertainLengthChange::Known(42), + } + ), + "Leufs42".to_string(), + ); + + assert_eq!( + format!( + "{}", + ProteinEdit::Fs { + alternative: None, + terminal: Some("Ter".to_string()), + length: UncertainLengthChange::None, + } + ), + "fsTer".to_string(), + ); + assert_eq!( + format!( + "{}", + ProteinEdit::Fs { + alternative: None, + terminal: Some("Ter".to_string()), + length: UncertainLengthChange::Unknown, + } + ), + "fsTer?".to_string(), + ); + assert_eq!( + format!( + "{}", + ProteinEdit::Fs { + alternative: None, + terminal: Some("Ter".to_string()), + length: UncertainLengthChange::Known(42), + } + ), + "fsTer42".to_string(), + ); + + assert_eq!( + format!( + "{}", + ProteinEdit::Fs { + alternative: Some("Leu".to_string()), + terminal: Some("Ter".to_string()), + length: UncertainLengthChange::None, + } + ), + "LeufsTer".to_string(), + ); + assert_eq!( + format!( + "{}", + ProteinEdit::Fs { + alternative: Some("Leu".to_string()), + terminal: Some("Ter".to_string()), + length: UncertainLengthChange::Unknown, + } + ), + "LeufsTer?".to_string(), + ); + assert_eq!( + format!( + "{}", + ProteinEdit::Fs { + alternative: Some("Leu".to_string()), + terminal: Some("Ter".to_string()), + length: UncertainLengthChange::Known(42), + } + ), + "LeufsTer42".to_string(), + ); + } + + #[test] + fn protein_edit_ext() { + assert_eq!( + format!( + "{}", + ProteinEdit::Ext { + aa_ext: None, + ext_aa: None, + change: UncertainLengthChange::None, + } + ), + "ext".to_string(), + ); + assert_eq!( + format!( + "{}", + ProteinEdit::Ext { + aa_ext: None, + ext_aa: None, + change: UncertainLengthChange::Unknown, + } + ), + "ext?".to_string(), + ); + assert_eq!( + format!( + "{}", + ProteinEdit::Ext { + aa_ext: None, + ext_aa: None, + change: UncertainLengthChange::Known(42), + } + ), + "ext42".to_string(), + ); + + assert_eq!( + format!( + "{}", + ProteinEdit::Ext { + aa_ext: Some("Leu".to_string()), + ext_aa: None, + change: UncertainLengthChange::None, + } + ), + "Leuext".to_string(), + ); + assert_eq!( + format!( + "{}", + ProteinEdit::Ext { + aa_ext: Some("Leu".to_string()), + ext_aa: None, + change: UncertainLengthChange::Unknown, + } + ), + "Leuext?".to_string(), + ); + assert_eq!( + format!( + "{}", + ProteinEdit::Ext { + aa_ext: Some("Leu".to_string()), + ext_aa: None, + change: UncertainLengthChange::Known(42), + } + ), + "Leuext42".to_string(), + ); + + assert_eq!( + format!( + "{}", + ProteinEdit::Ext { + aa_ext: None, + ext_aa: Some("Thr".to_string()), + change: UncertainLengthChange::None, + } + ), + "extThr".to_string(), + ); + assert_eq!( + format!( + "{}", + ProteinEdit::Ext { + aa_ext: None, + ext_aa: Some("Thr".to_string()), + change: UncertainLengthChange::Unknown, + } + ), + "extThr?".to_string(), + ); + assert_eq!( + format!( + "{}", + ProteinEdit::Ext { + aa_ext: None, + ext_aa: Some("Thr".to_string()), + change: UncertainLengthChange::Known(42), + } + ), + "extThr42".to_string(), + ); + + assert_eq!( + format!( + "{}", + ProteinEdit::Ext { + aa_ext: Some("Leu".to_string()), + ext_aa: Some("Thr".to_string()), + change: UncertainLengthChange::None, + } + ), + "LeuextThr".to_string(), + ); + assert_eq!( + format!( + "{}", + ProteinEdit::Ext { + aa_ext: Some("Leu".to_string()), + ext_aa: Some("Thr".to_string()), + change: UncertainLengthChange::Unknown, + } + ), + "LeuextThr?".to_string(), + ); + assert_eq!( + format!( + "{}", + ProteinEdit::Ext { + aa_ext: Some("Leu".to_string()), + ext_aa: Some("Thr".to_string()), + change: UncertainLengthChange::Known(42), + } + ), + "LeuextThr42".to_string(), + ); + } + + #[test] + fn protein_edit_subst() { + assert_eq!( + format!( + "{}", + ProteinEdit::Subst { + alternative: "Leu".to_string() + } + ), + "Leu".to_string(), + ); + } + + #[test] + fn protein_edit_del_ins() { + assert_eq!( + format!( + "{}", + ProteinEdit::DelIns { + alternative: "Leu".to_string() + } + ), + "delinsLeu".to_string(), + ); + } + + #[test] + fn protein_edit_ins() { + assert_eq!( + format!( + "{}", + ProteinEdit::Ins { + alternative: "Leu".to_string() + } + ), + "insLeu".to_string(), + ); + } + + #[test] + fn protein_edit_del() { + assert_eq!(format!("{}", ProteinEdit::Del), "del".to_string(),); + } + + #[test] + fn protein_edit_dup() { + assert_eq!(format!("{}", ProteinEdit::Dup), "dup".to_string(),); + } + + #[test] + fn protein_edit_ident() { + assert_eq!(format!("{}", ProteinEdit::Ident), "=".to_string(),); + } + + #[test] + fn cds_pos() { + assert_eq!( + format!( + "{}", + CdsPos { + base: 42, + offset: None, + cds_from: CdsFrom::Start, + } + ), + "42".to_string(), + ); + + assert_eq!( + format!( + "{}", + CdsPos { + base: 42, + offset: None, + cds_from: CdsFrom::End, + } + ), + "*42".to_string(), + ); + + assert_eq!( + format!( + "{}", + CdsPos { + base: 42, + offset: Some(10), + cds_from: CdsFrom::Start, + } + ), + "42+10".to_string(), + ); + + assert_eq!( + format!( + "{}", + CdsPos { + base: 42, + offset: Some(10), + cds_from: CdsFrom::End, + } + ), + "*42+10".to_string(), + ); + + assert_eq!( + format!( + "{}", + CdsPos { + base: 42, + offset: Some(-10), + cds_from: CdsFrom::Start, + } + ), + "42-10".to_string(), + ); + + assert_eq!( + format!( + "{}", + CdsPos { + base: 42, + offset: Some(-10), + cds_from: CdsFrom::End, + } + ), + "*42-10".to_string(), + ); + } + + #[test] + fn cds_interval() { + assert_eq!( + format!( + "{}", + CdsInterval { + begin: CdsPos { + base: 42, + offset: Some(-10), + cds_from: CdsFrom::Start, + }, + end: CdsPos { + base: 42, + offset: Some(10), + cds_from: CdsFrom::Start, + } + } + ), + "42-10_42+10".to_string(), + ); + } + + #[test] + fn cds_loc_edit() { + assert_eq!( + format!( + "{}", + CdsLocEdit { + loc: Mu::Certain(CdsInterval { + begin: CdsPos { + base: 42, + offset: Some(-10), + cds_from: CdsFrom::Start, + }, + end: CdsPos { + base: 42, + offset: Some(10), + cds_from: CdsFrom::Start, + } + }), + edit: Mu::Certain(NaEdit::RefAlt { + reference: "".to_string(), + alternative: "".to_string() + }) + } + ), + "42-10_42+10=".to_string(), + ); + } +} diff --git a/src/parser/mod.rs b/src/parser/mod.rs index ffbaf3a..fdc12cc 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -4,14 +4,16 @@ //! The data structures also provide the `Display` trait for conversion to //! strings etc. +mod display; mod ds; mod impl_parse; mod parse_funcs; use std::str::FromStr; +pub use crate::parser::display::*; pub use crate::parser::ds::*; -pub use crate::parser::impl_parse::*; +use crate::parser::impl_parse::*; impl FromStr for HgvsVariant { type Err = anyhow::Error; @@ -33,7 +35,7 @@ mod test { use crate::parser::{Accession, CdsFrom, CdsInterval, CdsLocEdit, CdsPos, Mu, NaEdit}; - use super::{HgvsVariant, Parseable}; + use super::HgvsVariant; #[test] fn from_str_basic() -> Result<(), anyhow::Error> { @@ -69,10 +71,9 @@ mod test { } #[test] - fn x() -> Result<(), anyhow::Error> { - // HgvsVariant::from_str("AC_01234.5:c.76_78del")?; - // CdsLocEdit::parse("76_78del")?; - CdsInterval::parse("76_78")?; + fn not_ok() -> Result<(), anyhow::Error> { + assert!(!HgvsVariant::from_str("x").is_ok()); + Ok(()) } diff --git a/tests/data/reject b/tests/data/reject index 385b0b6..cd1a894 100644 --- a/tests/data/reject +++ b/tests/data/reject @@ -1 +1,5 @@ #NC_000001.10:g.155208383_155208384dup2 dupN is not valid HGVS + +x + +#previous line is empty From 97d48c6d45f6cb80ab77dc5b939f5413ca2e0f06 Mon Sep 17 00:00:00 2001 From: Manuel Holtgrewe Date: Wed, 15 Feb 2023 13:07:13 +0100 Subject: [PATCH 02/10] wip --- src/parser/display.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/parser/display.rs b/src/parser/display.rs index 69b6ee7..238c627 100644 --- a/src/parser/display.rs +++ b/src/parser/display.rs @@ -143,7 +143,11 @@ impl Display for CdsLocEdit { impl Display for CdsInterval { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}_{}", self.begin, self.end) + write!(f, "{}", self.begin)?; + if self.begin != self.end { + write!(f, "_{}", self.end)?; + } + Ok(()) } } @@ -811,6 +815,25 @@ mod test { ), "42-10_42+10".to_string(), ); + + assert_eq!( + format!( + "{}", + CdsInterval { + begin: CdsPos { + base: 42, + offset: Some(10), + cds_from: CdsFrom::Start, + }, + end: CdsPos { + base: 42, + offset: Some(10), + cds_from: CdsFrom::Start, + } + } + ), + "42+10".to_string(), + ); } #[test] From 00f2cb3a739e8a45dc05150ea7f08de6f70aae4d Mon Sep 17 00:00:00 2001 From: Manuel Holtgrewe Date: Wed, 15 Feb 2023 13:10:52 +0100 Subject: [PATCH 03/10] tx and rna --- src/parser/display.rs | 261 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 260 insertions(+), 1 deletion(-) diff --git a/src/parser/display.rs b/src/parser/display.rs index 238c627..409560c 100644 --- a/src/parser/display.rs +++ b/src/parser/display.rs @@ -170,13 +170,75 @@ impl Display for CdsPos { } } +impl Display for TxLocEdit { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}{}", self.loc, self.edit) + } +} + +impl Display for TxInterval { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.begin)?; + if self.begin != self.end { + write!(f, "_{}", self.end)?; + } + Ok(()) + } +} + +impl Display for TxPos { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.base)?; + + if let Some(offset) = self.offset { + if offset > 0 { + write!(f, "+")?; + } + write!(f, "{}", offset)?; + } + + Ok(()) + } +} + +impl Display for RnaLocEdit { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}{}", self.loc, self.edit) + } +} + +impl Display for RnaInterval { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.begin)?; + if self.begin != self.end { + write!(f, "_{}", self.end)?; + } + Ok(()) + } +} + +impl Display for RnaPos { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.base)?; + + if let Some(offset) = self.offset { + if offset > 0 { + write!(f, "+")?; + } + write!(f, "{}", offset)?; + } + + Ok(()) + } +} + #[cfg(test)] mod test { use pretty_assertions::assert_eq; use crate::parser::{ Accession, CdsFrom, CdsInterval, CdsLocEdit, CdsPos, GeneSymbol, Mu, NaEdit, ProteinEdit, - UncertainLengthChange, + RnaInterval, RnaLocEdit, RnaPos, TxInterval, TxLocEdit, TxPos, UncertainLengthChange, }; #[test] @@ -863,4 +925,201 @@ mod test { "42-10_42+10=".to_string(), ); } + + #[test] + fn tx_pos() { + assert_eq!( + format!( + "{}", + TxPos { + base: 42, + offset: None, + } + ), + "42".to_string(), + ); + + assert_eq!( + format!( + "{}", + TxPos { + base: 42, + offset: Some(10), + } + ), + "42+10".to_string(), + ); + + assert_eq!( + format!( + "{}", + TxPos { + base: 42, + offset: Some(-10), + } + ), + "42-10".to_string(), + ); + } + + #[test] + fn tx_interval() { + assert_eq!( + format!( + "{}", + TxInterval { + begin: TxPos { + base: 42, + offset: Some(-10), + }, + end: TxPos { + base: 42, + offset: Some(10), + } + } + ), + "42-10_42+10".to_string(), + ); + + assert_eq!( + format!( + "{}", + TxInterval { + begin: TxPos { + base: 42, + offset: Some(10), + }, + end: TxPos { + base: 42, + offset: Some(10), + } + } + ), + "42+10".to_string(), + ); + } + + #[test] + fn tx_loc_edit() { + assert_eq!( + format!( + "{}", + TxLocEdit { + loc: Mu::Certain(TxInterval { + begin: TxPos { + base: 42, + offset: Some(-10), + }, + end: TxPos { + base: 42, + offset: Some(10), + } + }), + edit: Mu::Certain(NaEdit::RefAlt { + reference: "".to_string(), + alternative: "".to_string() + }) + } + ), + "42-10_42+10=".to_string(), + ); + } + #[test] + fn rna_pos() { + assert_eq!( + format!( + "{}", + RnaPos { + base: 42, + offset: None, + } + ), + "42".to_string(), + ); + + assert_eq!( + format!( + "{}", + RnaPos { + base: 42, + offset: Some(10), + } + ), + "42+10".to_string(), + ); + + assert_eq!( + format!( + "{}", + RnaPos { + base: 42, + offset: Some(-10), + } + ), + "42-10".to_string(), + ); + } + + #[test] + fn rna_interval() { + assert_eq!( + format!( + "{}", + RnaInterval { + begin: RnaPos { + base: 42, + offset: Some(-10), + }, + end: RnaPos { + base: 42, + offset: Some(10), + } + } + ), + "42-10_42+10".to_string(), + ); + + assert_eq!( + format!( + "{}", + RnaInterval { + begin: RnaPos { + base: 42, + offset: Some(10), + }, + end: RnaPos { + base: 42, + offset: Some(10), + } + } + ), + "42+10".to_string(), + ); + } + + #[test] + fn rna_loc_edit() { + assert_eq!( + format!( + "{}", + RnaLocEdit { + loc: Mu::Certain(RnaInterval { + begin: RnaPos { + base: 42, + offset: Some(-10), + }, + end: RnaPos { + base: 42, + offset: Some(10), + } + }), + edit: Mu::Certain(NaEdit::RefAlt { + reference: "".to_string(), + alternative: "".to_string() + }) + } + ), + "42-10_42+10=".to_string(), + ); + } } From 23fbac37904f2faad3d0579397e31b082f0b779d Mon Sep 17 00:00:00 2001 From: Manuel Holtgrewe Date: Wed, 15 Feb 2023 13:30:38 +0100 Subject: [PATCH 04/10] wip --- src/parser/display.rs | 395 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 393 insertions(+), 2 deletions(-) diff --git a/src/parser/display.rs b/src/parser/display.rs index 409560c..bbcdaa5 100644 --- a/src/parser/display.rs +++ b/src/parser/display.rs @@ -135,6 +135,34 @@ impl Display for ProteinEdit { } } +impl Display for ProtPos { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}{}", self.aa, self.number) + } +} + +impl Display for ProtInterval { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.begin)?; + if self.begin != self.end { + write!(f, "_{}", self.end)?; + } + Ok(()) + } +} + +impl Display for ProtLocEdit { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ProtLocEdit::Ordinary { loc, edit } => write!(f, "{}{}", loc, edit), + ProtLocEdit::NoChange => write!(f, "="), + ProtLocEdit::NoChangeUncertain => write!(f, "(=)"), + ProtLocEdit::NoProtein => write!(f, "0"), + ProtLocEdit::NoProteinUncertain => write!(f, "0?"), + } + } +} + impl Display for CdsLocEdit { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}{}", self.loc, self.edit) @@ -232,13 +260,132 @@ impl Display for RnaPos { } } +impl Display for GenomeLocEdit { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}{}", self.loc, self.edit) + } +} + +impl Display for GenomeInterval { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.begin { + Some(begin) => write!(f, "{}", begin)?, + None => write!(f, "?")?, + } + if self.begin != self.end { + match self.end { + Some(end) => write!(f, "_{}", end)?, + None => write!(f, "_?")?, + } + } + Ok(()) + } +} + +impl Display for MtLocEdit { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}{}", self.loc, self.edit) + } +} + +impl Display for MtInterval { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.begin { + Some(begin) => write!(f, "{}", begin)?, + None => write!(f, "?")?, + } + if self.begin != self.end { + match self.end { + Some(end) => write!(f, "_{}", end)?, + None => write!(f, "_?")?, + } + } + Ok(()) + } +} + +impl Display for HgvsVariant { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + HgvsVariant::CdsVariant { + accession, + gene_symbol, + loc_edit, + } => { + write!(f, "{}", accession)?; + if let Some(gene_symbol) = gene_symbol { + write!(f, "{}", gene_symbol)?; + } + write!(f, "{}", loc_edit) + } + HgvsVariant::GenomeVariant { + accession, + gene_symbol, + loc_edit, + } => { + write!(f, "{}", accession)?; + if let Some(gene_symbol) = gene_symbol { + write!(f, "{}", gene_symbol)?; + } + write!(f, "{}", loc_edit) + } + HgvsVariant::MtVariant { + accession, + gene_symbol, + loc_edit, + } => { + write!(f, "{}", accession)?; + if let Some(gene_symbol) = gene_symbol { + write!(f, "{}", gene_symbol)?; + } + write!(f, "{}", loc_edit) + } + HgvsVariant::TxVariant { + accession, + gene_symbol, + loc_edit, + } => { + write!(f, "{}", accession)?; + if let Some(gene_symbol) = gene_symbol { + write!(f, "{}", gene_symbol)?; + } + write!(f, "{}", loc_edit) + } + HgvsVariant::ProtVariant { + accession, + gene_symbol, + loc_edit, + } => { + write!(f, "{}", accession)?; + if let Some(gene_symbol) = gene_symbol { + write!(f, "{}", gene_symbol)?; + } + write!(f, "{}", loc_edit) + } + HgvsVariant::RnaVariant { + accession, + gene_symbol, + loc_edit, + } => { + write!(f, "{}", accession)?; + if let Some(gene_symbol) = gene_symbol { + write!(f, "{}", gene_symbol)?; + } + write!(f, "{}", loc_edit) + } + } + } +} + #[cfg(test)] mod test { use pretty_assertions::assert_eq; use crate::parser::{ - Accession, CdsFrom, CdsInterval, CdsLocEdit, CdsPos, GeneSymbol, Mu, NaEdit, ProteinEdit, - RnaInterval, RnaLocEdit, RnaPos, TxInterval, TxLocEdit, TxPos, UncertainLengthChange, + Accession, CdsFrom, CdsInterval, CdsLocEdit, CdsPos, GeneSymbol, GenomeInterval, + GenomeLocEdit, MtInterval, MtLocEdit, Mu, NaEdit, ProtInterval, ProtLocEdit, ProtPos, + ProteinEdit, RnaInterval, RnaLocEdit, RnaPos, TxInterval, TxLocEdit, TxPos, + UncertainLengthChange, }; #[test] @@ -1122,4 +1269,248 @@ mod test { "42-10_42+10=".to_string(), ); } + + #[test] + fn genome_interval() { + assert_eq!( + format!( + "{}", + GenomeInterval { + begin: None, + end: None + } + ), + "?".to_string(), + ); + + assert_eq!( + format!( + "{}", + GenomeInterval { + begin: Some(10), + end: None + } + ), + "10_?".to_string(), + ); + + assert_eq!( + format!( + "{}", + GenomeInterval { + begin: None, + end: Some(10) + } + ), + "?_10".to_string(), + ); + + assert_eq!( + format!( + "{}", + GenomeInterval { + begin: Some(10), + end: Some(20) + } + ), + "10_20".to_string(), + ); + + assert_eq!( + format!( + "{}", + GenomeInterval { + begin: Some(10), + end: Some(10) + } + ), + "10".to_string(), + ); + } + + #[test] + fn genome_loc_edit() { + assert_eq!( + format!( + "{}", + GenomeLocEdit { + loc: Mu::Certain(GenomeInterval { + begin: Some(10), + end: Some(20) + }), + edit: Mu::Certain(NaEdit::RefAlt { + reference: "C".to_string(), + alternative: "T".to_string() + }) + } + ), + "10_20C>T".to_string(), + ); + } + + #[test] + fn mt_interval() { + assert_eq!( + format!( + "{}", + MtInterval { + begin: None, + end: None + } + ), + "?".to_string(), + ); + + assert_eq!( + format!( + "{}", + MtInterval { + begin: Some(10), + end: None + } + ), + "10_?".to_string(), + ); + + assert_eq!( + format!( + "{}", + MtInterval { + begin: None, + end: Some(10) + } + ), + "?_10".to_string(), + ); + + assert_eq!( + format!( + "{}", + MtInterval { + begin: Some(10), + end: Some(20) + } + ), + "10_20".to_string(), + ); + + assert_eq!( + format!( + "{}", + MtInterval { + begin: Some(10), + end: Some(10) + } + ), + "10".to_string(), + ); + } + + #[test] + fn mt_loc_edit() { + assert_eq!( + format!( + "{}", + MtLocEdit { + loc: Mu::Certain(MtInterval { + begin: Some(10), + end: Some(20) + }), + edit: Mu::Certain(NaEdit::RefAlt { + reference: "C".to_string(), + alternative: "T".to_string() + }) + } + ), + "10_20C>T".to_string(), + ); + } + + #[test] + fn prot_pos() { + assert_eq!( + format!( + "{}", + ProtPos { + aa: "Leu".to_string(), + number: 42 + } + ), + "Leu42".to_string() + ); + } + + #[test] + fn prot_interval() { + assert_eq!( + format!( + "{}", + ProtInterval { + begin: ProtPos { + aa: "Leu".to_string(), + number: 42 + }, + end: ProtPos { + aa: "Thr".to_string(), + number: 43 + }, + } + ), + "Leu42_Thr43".to_string() + ); + + assert_eq!( + format!( + "{}", + ProtInterval { + begin: ProtPos { + aa: "Leu".to_string(), + number: 42 + }, + end: ProtPos { + aa: "Leu".to_string(), + number: 42 + }, + } + ), + "Leu42".to_string() + ); + } + + #[test] + fn prot_loc_edit() { + assert_eq!( + format!( + "{}", + ProtLocEdit::Ordinary { + loc: Mu::Certain(ProtInterval { + begin: ProtPos { + aa: "Leu".to_string(), + number: 42 + }, + end: ProtPos { + aa: "Thr".to_string(), + number: 43 + }, + },), + edit: Mu::Certain(ProteinEdit::Ident), + } + ), + "Leu42_Thr43=".to_string() + ); + + assert_eq!(format!("{}", ProtLocEdit::NoChange,), "=".to_string()); + + assert_eq!( + format!("{}", ProtLocEdit::NoChangeUncertain,), + "(=)".to_string() + ); + + assert_eq!(format!("{}", ProtLocEdit::NoProtein,), "0".to_string()); + + assert_eq!( + format!("{}", ProtLocEdit::NoProteinUncertain,), + "0?".to_string() + ); + } } From 824fc16f363fea475dc249bede919b31f324172c Mon Sep 17 00:00:00 2001 From: Manuel Holtgrewe Date: Wed, 15 Feb 2023 13:42:53 +0100 Subject: [PATCH 05/10] wip --- src/parser/display.rs | 343 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 329 insertions(+), 14 deletions(-) diff --git a/src/parser/display.rs b/src/parser/display.rs index bbcdaa5..c6481bb 100644 --- a/src/parser/display.rs +++ b/src/parser/display.rs @@ -314,9 +314,9 @@ impl Display for HgvsVariant { } => { write!(f, "{}", accession)?; if let Some(gene_symbol) = gene_symbol { - write!(f, "{}", gene_symbol)?; + write!(f, "({})", gene_symbol)?; } - write!(f, "{}", loc_edit) + write!(f, ":c.{}", loc_edit) } HgvsVariant::GenomeVariant { accession, @@ -325,9 +325,9 @@ impl Display for HgvsVariant { } => { write!(f, "{}", accession)?; if let Some(gene_symbol) = gene_symbol { - write!(f, "{}", gene_symbol)?; + write!(f, "({})", gene_symbol)?; } - write!(f, "{}", loc_edit) + write!(f, ":g.{}", loc_edit) } HgvsVariant::MtVariant { accession, @@ -336,9 +336,9 @@ impl Display for HgvsVariant { } => { write!(f, "{}", accession)?; if let Some(gene_symbol) = gene_symbol { - write!(f, "{}", gene_symbol)?; + write!(f, "({})", gene_symbol)?; } - write!(f, "{}", loc_edit) + write!(f, ":m.{}", loc_edit) } HgvsVariant::TxVariant { accession, @@ -347,9 +347,9 @@ impl Display for HgvsVariant { } => { write!(f, "{}", accession)?; if let Some(gene_symbol) = gene_symbol { - write!(f, "{}", gene_symbol)?; + write!(f, "({})", gene_symbol)?; } - write!(f, "{}", loc_edit) + write!(f, ":n.{}", loc_edit) } HgvsVariant::ProtVariant { accession, @@ -358,9 +358,9 @@ impl Display for HgvsVariant { } => { write!(f, "{}", accession)?; if let Some(gene_symbol) = gene_symbol { - write!(f, "{}", gene_symbol)?; + write!(f, "({})", gene_symbol)?; } - write!(f, "{}", loc_edit) + write!(f, ":p.{}", loc_edit) } HgvsVariant::RnaVariant { accession, @@ -369,9 +369,9 @@ impl Display for HgvsVariant { } => { write!(f, "{}", accession)?; if let Some(gene_symbol) = gene_symbol { - write!(f, "{}", gene_symbol)?; + write!(f, "({})", gene_symbol)?; } - write!(f, "{}", loc_edit) + write!(f, ":r.{}", loc_edit) } } } @@ -383,8 +383,8 @@ mod test { use crate::parser::{ Accession, CdsFrom, CdsInterval, CdsLocEdit, CdsPos, GeneSymbol, GenomeInterval, - GenomeLocEdit, MtInterval, MtLocEdit, Mu, NaEdit, ProtInterval, ProtLocEdit, ProtPos, - ProteinEdit, RnaInterval, RnaLocEdit, RnaPos, TxInterval, TxLocEdit, TxPos, + GenomeLocEdit, HgvsVariant, MtInterval, MtLocEdit, Mu, NaEdit, ProtInterval, ProtLocEdit, + ProtPos, ProteinEdit, RnaInterval, RnaLocEdit, RnaPos, TxInterval, TxLocEdit, TxPos, UncertainLengthChange, }; @@ -1513,4 +1513,319 @@ mod test { "0?".to_string() ); } + + #[test] + fn hgvs_variant_cds() { + assert_eq!( + format!( + "{}", + HgvsVariant::CdsVariant { + accession: Accession { + value: "NA12345.1".to_string() + }, + gene_symbol: Some(GeneSymbol { + value: "TTN".to_string() + }), + loc_edit: CdsLocEdit { + loc: Mu::Certain(CdsInterval { + begin: CdsPos { + base: 100, + offset: None, + cds_from: CdsFrom::Start, + }, + end: CdsPos { + base: 100, + offset: None, + cds_from: CdsFrom::Start, + } + }), + edit: Mu::Certain(NaEdit::RefAlt { + reference: "C".to_string(), + alternative: "T".to_string() + }) + } + } + ), + "NA12345.1(TTN):c.100C>T".to_string(), + ); + + assert_eq!( + format!( + "{}", + HgvsVariant::CdsVariant { + accession: Accession { + value: "NA12345.1".to_string() + }, + gene_symbol: None, + loc_edit: CdsLocEdit { + loc: Mu::Certain(CdsInterval { + begin: CdsPos { + base: 100, + offset: None, + cds_from: CdsFrom::Start, + }, + end: CdsPos { + base: 100, + offset: None, + cds_from: CdsFrom::Start, + } + }), + edit: Mu::Certain(NaEdit::RefAlt { + reference: "C".to_string(), + alternative: "T".to_string() + }) + } + } + ), + "NA12345.1:c.100C>T".to_string(), + ); + } + + #[test] + fn hgvs_variant_genome() { + assert_eq!( + format!( + "{}", + HgvsVariant::GenomeVariant { + accession: Accession { + value: "NA12345.1".to_string() + }, + gene_symbol: Some(GeneSymbol { + value: "TTN".to_string() + }), + loc_edit: GenomeLocEdit { + loc: Mu::Certain(GenomeInterval { + begin: Some(100), + end: Some(100) + }), + edit: Mu::Certain(NaEdit::RefAlt { + reference: "C".to_string(), + alternative: "T".to_string() + }) + } + } + ), + "NA12345.1(TTN):g.100C>T".to_string(), + ); + + assert_eq!( + format!( + "{}", + HgvsVariant::GenomeVariant { + accession: Accession { + value: "NA12345.1".to_string() + }, + gene_symbol: None, + loc_edit: GenomeLocEdit { + loc: Mu::Certain(GenomeInterval { + begin: Some(100), + end: Some(100) + }), + edit: Mu::Certain(NaEdit::RefAlt { + reference: "C".to_string(), + alternative: "T".to_string() + }) + } + } + ), + "NA12345.1:g.100C>T".to_string(), + ); + } + + #[test] + fn hgvs_variant_mt() { + assert_eq!( + format!( + "{}", + HgvsVariant::MtVariant { + accession: Accession { + value: "NA12345.1".to_string() + }, + gene_symbol: Some(GeneSymbol { + value: "TTN".to_string() + }), + loc_edit: MtLocEdit { + loc: Mu::Certain(MtInterval { + begin: Some(100), + end: Some(100) + }), + edit: Mu::Certain(NaEdit::RefAlt { + reference: "C".to_string(), + alternative: "T".to_string() + }) + } + } + ), + "NA12345.1(TTN):m.100C>T".to_string(), + ); + + assert_eq!( + format!( + "{}", + HgvsVariant::MtVariant { + accession: Accession { + value: "NA12345.1".to_string() + }, + gene_symbol: None, + loc_edit: MtLocEdit { + loc: Mu::Certain(MtInterval { + begin: Some(100), + end: Some(100) + }), + edit: Mu::Certain(NaEdit::RefAlt { + reference: "C".to_string(), + alternative: "T".to_string() + }) + } + } + ), + "NA12345.1:m.100C>T".to_string(), + ); + } + + #[test] + fn hgvs_variant_tx() { + assert_eq!( + format!( + "{}", + HgvsVariant::TxVariant { + accession: Accession { + value: "NA12345.1".to_string() + }, + gene_symbol: Some(GeneSymbol { + value: "TTN".to_string() + }), + loc_edit: TxLocEdit { + loc: Mu::Certain(TxInterval { + begin: TxPos { + base: 100, + offset: None + }, + end: TxPos { + base: 100, + offset: None + }, + }), + edit: Mu::Certain(NaEdit::RefAlt { + reference: "C".to_string(), + alternative: "T".to_string() + }) + } + } + ), + "NA12345.1(TTN):n.100C>T".to_string(), + ); + + assert_eq!( + format!( + "{}", + HgvsVariant::TxVariant { + accession: Accession { + value: "NA12345.1".to_string() + }, + gene_symbol: None, + loc_edit: TxLocEdit { + loc: Mu::Certain(TxInterval { + begin: TxPos { + base: 100, + offset: None + }, + end: TxPos { + base: 100, + offset: None + }, + }), + edit: Mu::Certain(NaEdit::RefAlt { + reference: "C".to_string(), + alternative: "T".to_string() + }) + } + } + ), + "NA12345.1:n.100C>T".to_string(), + ); + } + + #[test] + fn hgvs_variant_rna() { + assert_eq!( + format!( + "{}", + HgvsVariant::RnaVariant { + accession: Accession { + value: "NA12345.1".to_string() + }, + gene_symbol: Some(GeneSymbol { + value: "TTN".to_string() + }), + loc_edit: RnaLocEdit { + loc: Mu::Certain(RnaInterval { + begin: RnaPos { + base: 100, + offset: None + }, + end: RnaPos { + base: 100, + offset: None + }, + }), + edit: Mu::Certain(NaEdit::RefAlt { + reference: "C".to_string(), + alternative: "T".to_string() + }) + } + } + ), + "NA12345.1(TTN):r.100C>T".to_string(), + ); + + assert_eq!( + format!( + "{}", + HgvsVariant::RnaVariant { + accession: Accession { + value: "NA12345.1".to_string() + }, + gene_symbol: None, + loc_edit: RnaLocEdit { + loc: Mu::Certain(RnaInterval { + begin: RnaPos { + base: 100, + offset: None + }, + end: RnaPos { + base: 100, + offset: None + }, + }), + edit: Mu::Certain(NaEdit::RefAlt { + reference: "C".to_string(), + alternative: "T".to_string() + }) + } + } + ), + "NA12345.1:r.100C>T".to_string(), + ); + } + + + #[test] + fn hgvs_variant_prot() { + assert_eq!( + format!( + "{}", + HgvsVariant::ProtVariant { + accession: Accession { + value: "NA12345.1".to_string() + }, + gene_symbol: Some(GeneSymbol { + value: "TTN".to_string() + }), + loc_edit: ProtLocEdit::NoChange + } + ), + "NA12345.1(TTN):p.=".to_string(), + ); + } } From 55064bade2ae9a01966bddb1f920078d68179b3f Mon Sep 17 00:00:00 2001 From: Manuel Holtgrewe Date: Wed, 15 Feb 2023 13:43:08 +0100 Subject: [PATCH 06/10] clippy fix --- src/parser/display.rs | 128 +++++++++++++++++++++--------------------- src/parser/mod.rs | 10 ++-- 2 files changed, 69 insertions(+), 69 deletions(-) diff --git a/src/parser/display.rs b/src/parser/display.rs index c6481bb..de134f6 100644 --- a/src/parser/display.rs +++ b/src/parser/display.rs @@ -10,8 +10,8 @@ where { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Mu::Certain(value) => write!(f, "{}", value), - Mu::Uncertain(value) => write!(f, "({})", value), + Mu::Certain(value) => write!(f, "{value}"), + Mu::Uncertain(value) => write!(f, "({value})"), } } } @@ -30,22 +30,22 @@ impl Display for NaEdit { alternative, } => match (reference.len(), alternative.len()) { (0, 0) => write!(f, "="), - (1, 1) => write!(f, "{}>{}", reference, alternative), - (0, _) => write!(f, "ins{}", alternative), - (_, 0) => write!(f, "del{}", reference), - (_, _) => write!(f, "del{}ins{}", reference, alternative), + (1, 1) => write!(f, "{reference}>{alternative}"), + (0, _) => write!(f, "ins{alternative}"), + (_, 0) => write!(f, "del{reference}"), + (_, _) => write!(f, "del{reference}ins{alternative}"), }, NaEdit::NumAlt { count, alternative } => match (count, alternative.len()) { (0, 0) => write!(f, "="), - (0, _) => write!(f, "ins{}", alternative), - (_, 0) => write!(f, "del{}", count), - (_, _) => write!(f, "del{}ins{}", count, alternative), + (0, _) => write!(f, "ins{alternative}"), + (_, 0) => write!(f, "del{count}"), + (_, _) => write!(f, "del{count}ins{alternative}"), }, - NaEdit::Del { reference } => write!(f, "del{}", reference), - NaEdit::Ins { alternative } => write!(f, "ins{}", alternative), - NaEdit::Dup { reference } => write!(f, "dup{}", reference), - NaEdit::InvRef { reference } => write!(f, "inv{}", reference), - NaEdit::InvNum { count } => write!(f, "inv{}", count), + NaEdit::Del { reference } => write!(f, "del{reference}"), + NaEdit::Ins { alternative } => write!(f, "ins{alternative}"), + NaEdit::Dup { reference } => write!(f, "dup{reference}"), + NaEdit::InvRef { reference } => write!(f, "inv{reference}"), + NaEdit::InvNum { count } => write!(f, "inv{count}"), } } } @@ -55,7 +55,7 @@ impl Display for UncertainLengthChange { match self { UncertainLengthChange::None => write!(f, ""), UncertainLengthChange::Unknown => write!(f, "?"), - UncertainLengthChange::Known(count) => write!(f, "{}", count), + UncertainLengthChange::Known(count) => write!(f, "{count}"), } } } @@ -76,25 +76,25 @@ impl Display for ProteinEdit { } => match (alternative, terminal, length) { (None, None, UncertainLengthChange::None) => write!(f, "fs"), (None, None, UncertainLengthChange::Unknown) => write!(f, "fs?"), - (None, None, UncertainLengthChange::Known(count)) => write!(f, "fs{}", count), - (Some(alt), None, UncertainLengthChange::None) => write!(f, "{}fs", alt), - (Some(alt), None, UncertainLengthChange::Unknown) => write!(f, "{}fs?", alt), + (None, None, UncertainLengthChange::Known(count)) => write!(f, "fs{count}"), + (Some(alt), None, UncertainLengthChange::None) => write!(f, "{alt}fs"), + (Some(alt), None, UncertainLengthChange::Unknown) => write!(f, "{alt}fs?"), (Some(alt), None, UncertainLengthChange::Known(count)) => { - write!(f, "{}fs{}", alt, count) + write!(f, "{alt}fs{count}") } - (None, Some(ter), UncertainLengthChange::None) => write!(f, "fs{}", ter), - (None, Some(ter), UncertainLengthChange::Unknown) => write!(f, "fs{}?", ter), + (None, Some(ter), UncertainLengthChange::None) => write!(f, "fs{ter}"), + (None, Some(ter), UncertainLengthChange::Unknown) => write!(f, "fs{ter}?"), (None, Some(ter), UncertainLengthChange::Known(count)) => { - write!(f, "fs{}{}", ter, count) + write!(f, "fs{ter}{count}") } (Some(alt), Some(ter), UncertainLengthChange::None) => { - write!(f, "{}fs{}", alt, ter) + write!(f, "{alt}fs{ter}") } (Some(alt), Some(ter), UncertainLengthChange::Unknown) => { - write!(f, "{}fs{}?", alt, ter) + write!(f, "{alt}fs{ter}?") } (Some(alt), Some(ter), UncertainLengthChange::Known(count)) => { - write!(f, "{}fs{}{}", alt, ter, count) + write!(f, "{alt}fs{ter}{count}") } }, ProteinEdit::Ext { @@ -104,30 +104,30 @@ impl Display for ProteinEdit { } => match (aa_ext, ext_aa, change) { (None, None, UncertainLengthChange::None) => write!(f, "ext"), (None, None, UncertainLengthChange::Unknown) => write!(f, "ext?"), - (None, None, UncertainLengthChange::Known(count)) => write!(f, "ext{}", count), - (Some(alt), None, UncertainLengthChange::None) => write!(f, "{}ext", alt), - (Some(alt), None, UncertainLengthChange::Unknown) => write!(f, "{}ext?", alt), + (None, None, UncertainLengthChange::Known(count)) => write!(f, "ext{count}"), + (Some(alt), None, UncertainLengthChange::None) => write!(f, "{alt}ext"), + (Some(alt), None, UncertainLengthChange::Unknown) => write!(f, "{alt}ext?"), (Some(alt), None, UncertainLengthChange::Known(count)) => { - write!(f, "{}ext{}", alt, count) + write!(f, "{alt}ext{count}") } - (None, Some(ter), UncertainLengthChange::None) => write!(f, "ext{}", ter), - (None, Some(ter), UncertainLengthChange::Unknown) => write!(f, "ext{}?", ter), + (None, Some(ter), UncertainLengthChange::None) => write!(f, "ext{ter}"), + (None, Some(ter), UncertainLengthChange::Unknown) => write!(f, "ext{ter}?"), (None, Some(ter), UncertainLengthChange::Known(count)) => { - write!(f, "ext{}{}", ter, count) + write!(f, "ext{ter}{count}") } (Some(alt), Some(ter), UncertainLengthChange::None) => { - write!(f, "{}ext{}", alt, ter) + write!(f, "{alt}ext{ter}") } (Some(alt), Some(ter), UncertainLengthChange::Unknown) => { - write!(f, "{}ext{}?", alt, ter) + write!(f, "{alt}ext{ter}?") } (Some(alt), Some(ter), UncertainLengthChange::Known(count)) => { - write!(f, "{}ext{}{}", alt, ter, count) + write!(f, "{alt}ext{ter}{count}") } }, - ProteinEdit::Subst { alternative } => write!(f, "{}", alternative), - ProteinEdit::DelIns { alternative } => write!(f, "delins{}", alternative), - ProteinEdit::Ins { alternative } => write!(f, "ins{}", alternative), + ProteinEdit::Subst { alternative } => write!(f, "{alternative}"), + ProteinEdit::DelIns { alternative } => write!(f, "delins{alternative}"), + ProteinEdit::Ins { alternative } => write!(f, "ins{alternative}"), ProteinEdit::Del => write!(f, "del"), ProteinEdit::Dup => write!(f, "dup"), ProteinEdit::Ident => write!(f, "="), @@ -154,7 +154,7 @@ impl Display for ProtInterval { impl Display for ProtLocEdit { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - ProtLocEdit::Ordinary { loc, edit } => write!(f, "{}{}", loc, edit), + ProtLocEdit::Ordinary { loc, edit } => write!(f, "{loc}{edit}"), ProtLocEdit::NoChange => write!(f, "="), ProtLocEdit::NoChangeUncertain => write!(f, "(=)"), ProtLocEdit::NoProtein => write!(f, "0"), @@ -191,7 +191,7 @@ impl Display for CdsPos { if offset > 0 { write!(f, "+")?; } - write!(f, "{}", offset)?; + write!(f, "{offset}")?; } Ok(()) @@ -222,7 +222,7 @@ impl Display for TxPos { if offset > 0 { write!(f, "+")?; } - write!(f, "{}", offset)?; + write!(f, "{offset}")?; } Ok(()) @@ -253,7 +253,7 @@ impl Display for RnaPos { if offset > 0 { write!(f, "+")?; } - write!(f, "{}", offset)?; + write!(f, "{offset}")?; } Ok(()) @@ -269,12 +269,12 @@ impl Display for GenomeLocEdit { impl Display for GenomeInterval { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self.begin { - Some(begin) => write!(f, "{}", begin)?, + Some(begin) => write!(f, "{begin}")?, None => write!(f, "?")?, } if self.begin != self.end { match self.end { - Some(end) => write!(f, "_{}", end)?, + Some(end) => write!(f, "_{end}")?, None => write!(f, "_?")?, } } @@ -291,12 +291,12 @@ impl Display for MtLocEdit { impl Display for MtInterval { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self.begin { - Some(begin) => write!(f, "{}", begin)?, + Some(begin) => write!(f, "{begin}")?, None => write!(f, "?")?, } if self.begin != self.end { match self.end { - Some(end) => write!(f, "_{}", end)?, + Some(end) => write!(f, "_{end}")?, None => write!(f, "_?")?, } } @@ -312,66 +312,66 @@ impl Display for HgvsVariant { gene_symbol, loc_edit, } => { - write!(f, "{}", accession)?; + write!(f, "{accession}")?; if let Some(gene_symbol) = gene_symbol { - write!(f, "({})", gene_symbol)?; + write!(f, "({gene_symbol})")?; } - write!(f, ":c.{}", loc_edit) + write!(f, ":c.{loc_edit}") } HgvsVariant::GenomeVariant { accession, gene_symbol, loc_edit, } => { - write!(f, "{}", accession)?; + write!(f, "{accession}")?; if let Some(gene_symbol) = gene_symbol { - write!(f, "({})", gene_symbol)?; + write!(f, "({gene_symbol})")?; } - write!(f, ":g.{}", loc_edit) + write!(f, ":g.{loc_edit}") } HgvsVariant::MtVariant { accession, gene_symbol, loc_edit, } => { - write!(f, "{}", accession)?; + write!(f, "{accession}")?; if let Some(gene_symbol) = gene_symbol { - write!(f, "({})", gene_symbol)?; + write!(f, "({gene_symbol})")?; } - write!(f, ":m.{}", loc_edit) + write!(f, ":m.{loc_edit}") } HgvsVariant::TxVariant { accession, gene_symbol, loc_edit, } => { - write!(f, "{}", accession)?; + write!(f, "{accession}")?; if let Some(gene_symbol) = gene_symbol { - write!(f, "({})", gene_symbol)?; + write!(f, "({gene_symbol})")?; } - write!(f, ":n.{}", loc_edit) + write!(f, ":n.{loc_edit}") } HgvsVariant::ProtVariant { accession, gene_symbol, loc_edit, } => { - write!(f, "{}", accession)?; + write!(f, "{accession}")?; if let Some(gene_symbol) = gene_symbol { - write!(f, "({})", gene_symbol)?; + write!(f, "({gene_symbol})")?; } - write!(f, ":p.{}", loc_edit) + write!(f, ":p.{loc_edit}") } HgvsVariant::RnaVariant { accession, gene_symbol, loc_edit, } => { - write!(f, "{}", accession)?; + write!(f, "{accession}")?; if let Some(gene_symbol) = gene_symbol { - write!(f, "({})", gene_symbol)?; + write!(f, "({gene_symbol})")?; } - write!(f, ":r.{}", loc_edit) + write!(f, ":r.{loc_edit}") } } } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index fdc12cc..de12640 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -72,7 +72,7 @@ mod test { #[test] fn not_ok() -> Result<(), anyhow::Error> { - assert!(!HgvsVariant::from_str("x").is_ok()); + assert!(HgvsVariant::from_str("x").is_err()); Ok(()) } @@ -85,8 +85,8 @@ mod test { for line in reader.lines() { let line = line?; let line = line.trim(); - if !line.starts_with("#") && !line.is_empty() { - assert!(HgvsVariant::from_str(line).is_ok(), "line = {}", line) + if !line.starts_with('#') && !line.is_empty() { + assert!(HgvsVariant::from_str(line).is_ok(), "line = {line}") } } @@ -101,8 +101,8 @@ mod test { for line in reader.lines() { let line = line?; let line = line.trim(); - if !line.starts_with("#") && !line.is_empty() { - assert!(!HgvsVariant::from_str(line).is_ok(), "line = {}", line) + if !line.starts_with('#') && !line.is_empty() { + assert!(HgvsVariant::from_str(line).is_err(), "line = {line}") } } From b4f95a8ffabc01d738b5a3f21b9e4e63b3652ed3 Mon Sep 17 00:00:00 2001 From: Manuel Holtgrewe Date: Wed, 15 Feb 2023 13:43:21 +0100 Subject: [PATCH 07/10] cargo fmt --- src/parser/display.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/parser/display.rs b/src/parser/display.rs index de134f6..aff5f4d 100644 --- a/src/parser/display.rs +++ b/src/parser/display.rs @@ -1809,7 +1809,6 @@ mod test { ); } - #[test] fn hgvs_variant_prot() { assert_eq!( From 282859c38e84a10286987dc9bb2056c0d947f9eb Mon Sep 17 00:00:00 2001 From: Manuel Holtgrewe Date: Wed, 15 Feb 2023 13:46:34 +0100 Subject: [PATCH 08/10] failing tests --- src/parser/display.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/parser/display.rs b/src/parser/display.rs index aff5f4d..541336f 100644 --- a/src/parser/display.rs +++ b/src/parser/display.rs @@ -379,6 +379,8 @@ impl Display for HgvsVariant { #[cfg(test)] mod test { + use std::{io::{BufReader, BufRead}, fs::File, str::FromStr}; + use pretty_assertions::assert_eq; use crate::parser::{ @@ -1827,4 +1829,28 @@ mod test { "NA12345.1(TTN):p.=".to_string(), ); } + + // This test uses the "gauntlet" file from the hgvs package for round-tripping. + #[test] + fn hgvs_gauntlet() -> Result<(), anyhow::Error> { + let reader = BufReader::new(File::open("tests/data/gauntlet")?); + + for line in reader.lines() { + let line = line?; + let line = line.trim(); + if !line.starts_with('#') && !line.is_empty() { + let hgvs_variant = HgvsVariant::from_str(line)?; + let hgvs_str = format!("{}", &hgvs_variant); + assert_eq!( + hgvs_str, + line, + "round-trip failed for variant {:?}", + &hgvs_variant + ); + } + } + + Ok(()) + } + } From 83c966e432ae6166edaf9dd960ed038400a27cc2 Mon Sep 17 00:00:00 2001 From: Manuel Holtgrewe Date: Wed, 15 Feb 2023 14:01:41 +0100 Subject: [PATCH 09/10] point of return --- src/parser/display.rs | 16 +++++++++------- src/parser/impl_parse.rs | 14 +++++++------- src/parser/mod.rs | 3 ++- src/parser/parse_funcs.rs | 8 +++----- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/parser/display.rs b/src/parser/display.rs index 541336f..1f0c0be 100644 --- a/src/parser/display.rs +++ b/src/parser/display.rs @@ -31,13 +31,13 @@ impl Display for NaEdit { } => match (reference.len(), alternative.len()) { (0, 0) => write!(f, "="), (1, 1) => write!(f, "{reference}>{alternative}"), - (0, _) => write!(f, "ins{alternative}"), + (0, _) => write!(f, "delins{alternative}"), (_, 0) => write!(f, "del{reference}"), (_, _) => write!(f, "del{reference}ins{alternative}"), }, NaEdit::NumAlt { count, alternative } => match (count, alternative.len()) { (0, 0) => write!(f, "="), - (0, _) => write!(f, "ins{alternative}"), + (0, _) => write!(f, "delins{alternative}"), (_, 0) => write!(f, "del{count}"), (_, _) => write!(f, "del{count}ins{alternative}"), }, @@ -379,7 +379,11 @@ impl Display for HgvsVariant { #[cfg(test)] mod test { - use std::{io::{BufReader, BufRead}, fs::File, str::FromStr}; + use std::{ + fs::File, + io::{BufRead, BufReader}, + str::FromStr, + }; use pretty_assertions::assert_eq; @@ -1832,7 +1836,7 @@ mod test { // This test uses the "gauntlet" file from the hgvs package for round-tripping. #[test] - fn hgvs_gauntlet() -> Result<(), anyhow::Error> { + fn roundtrip_hgvs_gauntlet() -> Result<(), anyhow::Error> { let reader = BufReader::new(File::open("tests/data/gauntlet")?); for line in reader.lines() { @@ -1842,8 +1846,7 @@ mod test { let hgvs_variant = HgvsVariant::from_str(line)?; let hgvs_str = format!("{}", &hgvs_variant); assert_eq!( - hgvs_str, - line, + hgvs_str, line, "round-trip failed for variant {:?}", &hgvs_variant ); @@ -1852,5 +1855,4 @@ mod test { Ok(()) } - } diff --git a/src/parser/impl_parse.rs b/src/parser/impl_parse.rs index 965425f..b359f69 100644 --- a/src/parser/impl_parse.rs +++ b/src/parser/impl_parse.rs @@ -5,7 +5,7 @@ use nom::{ bytes::complete::tag, character::complete::alphanumeric1, character::complete::char, - combinator::{map, opt, recognize}, + combinator::{all_consuming, map, opt, recognize}, sequence::{pair, tuple}, IResult, }; @@ -14,7 +14,7 @@ use crate::parser::ds::*; use crate::parser::parse_funcs::*; impl HgvsVariant { - fn parse_cds_variant(input: &str) -> IResult<&str, Self> { + pub fn parse_cds_variant(input: &str) -> IResult<&str, Self> { map( tuple(( Accession::parse, @@ -114,14 +114,14 @@ impl HgvsVariant { impl Parseable for HgvsVariant { /// Parse a `HgvsVariant` from the given `str`. fn parse(input: &str) -> IResult<&str, Self> { - alt(( + all_consuming(alt(( Self::parse_cds_variant, Self::parse_genome_variant, Self::parse_mt_variant, Self::parse_tx_variant, Self::parse_prot_variant, Self::parse_rna_variant, - ))(input) + )))(input) } } @@ -154,10 +154,10 @@ impl Parseable for NaEdit { alt(( na_edit::ident, na_edit::subst, - na_edit::del_ref, - na_edit::del_num, - na_edit::delins_ref_alt, na_edit::delins_num_alt, + na_edit::delins_ref_alt, + na_edit::del_num, + na_edit::del_ref, na_edit::ins, na_edit::dup, na_edit::inv_num, diff --git a/src/parser/mod.rs b/src/parser/mod.rs index de12640..5e8f053 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -86,7 +86,8 @@ mod test { let line = line?; let line = line.trim(); if !line.starts_with('#') && !line.is_empty() { - assert!(HgvsVariant::from_str(line).is_ok(), "line = {line}") + let result = HgvsVariant::from_str(line); + assert!(result.is_ok(), "line = {}; result = {:?}", &line, &result); } } diff --git a/src/parser/parse_funcs.rs b/src/parser/parse_funcs.rs index c0c49a1..76f7b80 100644 --- a/src/parser/parse_funcs.rs +++ b/src/parser/parse_funcs.rs @@ -352,11 +352,9 @@ pub mod na_edit { } pub fn del_num(input: &str) -> IResult<&str, NaEdit> { - map(tuple((tag("del"), digit1)), |(_, reference)| { - NaEdit::NumAlt { - count: str::parse::(reference).unwrap(), - alternative: "".to_string(), - } + map(tuple((tag("del"), digit1)), |(_, count)| NaEdit::NumAlt { + count: str::parse::(count).unwrap(), + alternative: "".to_string(), })(input) } From 7d3c1861b0775849e31cf3849b58bed0b7ecf598 Mon Sep 17 00:00:00 2001 From: Manuel Holtgrewe Date: Wed, 15 Feb 2023 14:20:13 +0100 Subject: [PATCH 10/10] roundtrip works now with hgvs examples --- src/parser/display.rs | 31 ++++++++++++++++++++----------- src/parser/ds.rs | 4 +++- src/parser/impl_parse.rs | 4 ++-- src/parser/parse_funcs.rs | 20 +++++--------------- 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/parser/display.rs b/src/parser/display.rs index 1f0c0be..dc86257 100644 --- a/src/parser/display.rs +++ b/src/parser/display.rs @@ -32,16 +32,17 @@ impl Display for NaEdit { (0, 0) => write!(f, "="), (1, 1) => write!(f, "{reference}>{alternative}"), (0, _) => write!(f, "delins{alternative}"), - (_, 0) => write!(f, "del{reference}"), + (_, 0) => write!(f, "del{reference}ins"), (_, _) => write!(f, "del{reference}ins{alternative}"), }, NaEdit::NumAlt { count, alternative } => match (count, alternative.len()) { (0, 0) => write!(f, "="), (0, _) => write!(f, "delins{alternative}"), - (_, 0) => write!(f, "del{count}"), + (_, 0) => write!(f, "del{count}ins"), (_, _) => write!(f, "del{count}ins{alternative}"), }, - NaEdit::Del { reference } => write!(f, "del{reference}"), + NaEdit::DelRef { reference } => write!(f, "del{reference}"), + NaEdit::DelNum { count } => write!(f, "del{count}"), NaEdit::Ins { alternative } => write!(f, "ins{alternative}"), NaEdit::Dup { reference } => write!(f, "dup{reference}"), NaEdit::InvRef { reference } => write!(f, "inv{reference}"), @@ -456,7 +457,7 @@ mod test { alternative: "".to_string() } ), - "delC".to_string() + "delCins".to_string() ); assert_eq!( @@ -467,7 +468,7 @@ mod test { alternative: "C".to_string() } ), - "insC".to_string() + "delinsC".to_string() ); } @@ -492,7 +493,7 @@ mod test { alternative: "T".to_string() } ), - "insT".to_string() + "delinsT".to_string() ); assert_eq!( format!( @@ -502,7 +503,7 @@ mod test { alternative: "".to_string() } ), - "del3".to_string() + "del3ins".to_string() ); assert_eq!( @@ -518,11 +519,11 @@ mod test { } #[test] - fn na_edit_del() { + fn na_edit_del_ref() { assert_eq!( format!( "{}", - NaEdit::Del { + NaEdit::DelRef { reference: "T".to_string() } ), @@ -530,6 +531,14 @@ mod test { ); } + #[test] + fn na_edit_del_num() { + assert_eq!( + format!("{}", NaEdit::DelNum { count: 3 }), + "del3".to_string() + ); + } + #[test] fn na_edit_ins() { assert_eq!( @@ -1847,8 +1856,8 @@ mod test { let hgvs_str = format!("{}", &hgvs_variant); assert_eq!( hgvs_str, line, - "round-trip failed for variant {:?}", - &hgvs_variant + "round-trip failed for variant {:?}; line= {}", + &hgvs_variant, line ); } } diff --git a/src/parser/ds.rs b/src/parser/ds.rs index 86668e6..c131b0a 100644 --- a/src/parser/ds.rs +++ b/src/parser/ds.rs @@ -27,7 +27,9 @@ pub enum NaEdit { /// A substitution where the reference is a number and alternative is a count. NumAlt { count: i32, alternative: String }, /// Deletion of one or more nucleic acid characters. - Del { reference: String }, + DelRef { reference: String }, + /// Deletion of a number of characters. + DelNum { count: i32 }, /// Insertion of one or more nucleic acid characters. Ins { alternative: String }, /// Duplication of nucleic acid reference sequence. diff --git a/src/parser/impl_parse.rs b/src/parser/impl_parse.rs index b359f69..2d5dcdb 100644 --- a/src/parser/impl_parse.rs +++ b/src/parser/impl_parse.rs @@ -141,9 +141,9 @@ impl Parseable for ProteinEdit { protein_edit::ident, protein_edit::subst_qm, protein_edit::subst_aa, - protein_edit::delins, protein_edit::del, protein_edit::ins, + protein_edit::delins, protein_edit::dup, ))(input) } @@ -154,8 +154,8 @@ impl Parseable for NaEdit { alt(( na_edit::ident, na_edit::subst, - na_edit::delins_num_alt, na_edit::delins_ref_alt, + na_edit::delins_num_alt, na_edit::del_num, na_edit::del_ref, na_edit::ins, diff --git a/src/parser/parse_funcs.rs b/src/parser/parse_funcs.rs index 76f7b80..9d1575d 100644 --- a/src/parser/parse_funcs.rs +++ b/src/parser/parse_funcs.rs @@ -345,16 +345,14 @@ pub mod na_edit { } pub fn del_ref(input: &str) -> IResult<&str, NaEdit> { - map(tuple((tag("del"), na0)), |(_, reference)| NaEdit::RefAlt { + map(tuple((tag("del"), na0)), |(_, reference)| NaEdit::DelRef { reference: reference.to_string(), - alternative: "".to_string(), })(input) } pub fn del_num(input: &str) -> IResult<&str, NaEdit> { - map(tuple((tag("del"), digit1)), |(_, count)| NaEdit::NumAlt { + map(tuple((tag("del"), digit1)), |(_, count)| NaEdit::DelNum { count: str::parse::(count).unwrap(), - alternative: "".to_string(), })(input) } @@ -1433,9 +1431,8 @@ mod test { na_edit::del_ref("delT"), Ok(( "", - NaEdit::RefAlt { + NaEdit::DelRef { reference: "T".to_owned(), - alternative: "".to_owned(), } )) ); @@ -1443,9 +1440,8 @@ mod test { na_edit::del_ref("del"), Ok(( "", - NaEdit::RefAlt { + NaEdit::DelRef { reference: "".to_owned(), - alternative: "".to_owned(), } )) ); @@ -1455,13 +1451,7 @@ mod test { fn naedit_del_num() { assert_eq!( na_edit::del_num("del3"), - Ok(( - "", - NaEdit::NumAlt { - count: 3, - alternative: "".to_owned(), - } - )) + Ok(("", NaEdit::DelNum { count: 3 })) ); }