|
|
@@ -1,276 +1,260 @@
|
|
|
+use anyhow::{anyhow, Context, Ok};
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
+use std::{fmt, str::FromStr};
|
|
|
+
|
|
|
+#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
+pub struct Variant {
|
|
|
+ pub contig: String,
|
|
|
+ pub position: u32,
|
|
|
+ pub id: String,
|
|
|
+ pub reference: ReferenceAlternative,
|
|
|
+ pub alternative: ReferenceAlternative,
|
|
|
+ pub quality: Option<f32>,
|
|
|
+ pub filter: Filter,
|
|
|
+ pub info: String,
|
|
|
+ pub formats: Formats,
|
|
|
+ pub annotations: Vec<Annotation>,
|
|
|
+}
|
|
|
|
|
|
-#[derive(Debug, Clone, Serialize, Eq, PartialEq, Deserialize)]
|
|
|
-pub enum VariantType {
|
|
|
- Somatic,
|
|
|
- Constitutionnal,
|
|
|
+impl PartialEq for Variant {
|
|
|
+ fn eq(&self, other: &Self) -> bool {
|
|
|
+ // Nota bene: id, filter, info, format and quality is intentionally not compared
|
|
|
+ self.contig == other.contig
|
|
|
+ && self.position == other.position
|
|
|
+ && self.reference == other.reference
|
|
|
+ && self.alternative == other.alternative
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+impl Eq for Variant {}
|
|
|
+impl FromStr for Variant {
|
|
|
+ type Err = anyhow::Error;
|
|
|
|
|
|
+ fn from_str(s: &str) -> anyhow::Result<Self> {
|
|
|
+ let v: Vec<&str> = s.split('\t').collect();
|
|
|
|
|
|
-impl Variant {
|
|
|
- pub fn from_vcfrow(row: &VCFRow, source: VCFSource, variant_type: VariantType) -> anyhow::Result<Self> {
|
|
|
- let callers_data = vec![CallerData {
|
|
|
- qual: row.qual.parse::<f32>().ok(),
|
|
|
- info: parse_info(&row.info, &source).context(anyhow!(
|
|
|
- "Can't parse {:?} info for {}",
|
|
|
- source,
|
|
|
- row.info
|
|
|
- ))?,
|
|
|
- format: parse_format(&source, &row.value).context(anyhow!(
|
|
|
- "Can't parse {:?} format for {}",
|
|
|
- source,
|
|
|
- row.value
|
|
|
- ))?,
|
|
|
- }];
|
|
|
-
|
|
|
- Ok(Variant {
|
|
|
- contig: row.chr.to_string(),
|
|
|
- position: row.pos,
|
|
|
- reference: row
|
|
|
- .reference
|
|
|
+ let formats = if v.len() == 10 {
|
|
|
+ (
|
|
|
+ *v.get(8).ok_or(anyhow!("Can't parse formats from: {s}"))?,
|
|
|
+ *v.get(9).ok_or(anyhow!("Can't parse formats from: {s}"))?,
|
|
|
+ )
|
|
|
+ .try_into()
|
|
|
+ .context(format!("Can't parse formats from: {s}"))?
|
|
|
+ } else {
|
|
|
+ Formats::default()
|
|
|
+ };
|
|
|
+
|
|
|
+ Ok(Self {
|
|
|
+ contig: v
|
|
|
+ .first()
|
|
|
+ .ok_or(anyhow!("Can't parse contig from: {s}"))?
|
|
|
+ .to_string(),
|
|
|
+ position: v
|
|
|
+ .get(1)
|
|
|
+ .ok_or(anyhow!("Can't parse contig from: {s}"))?
|
|
|
+ .parse()
|
|
|
+ .context(format!("Can't parse position from: {s}"))?,
|
|
|
+ id: v
|
|
|
+ .get(2)
|
|
|
+ .ok_or(anyhow!("Can't parse id from: {s}"))?
|
|
|
+ .to_string(),
|
|
|
+ reference: v
|
|
|
+ .get(3)
|
|
|
+ .ok_or(anyhow!("Can't parse reference from: {s}"))?
|
|
|
+ .parse()
|
|
|
+ .context(format!("Can't parse reference from: {s}"))?,
|
|
|
+ alternative: v
|
|
|
+ .get(4)
|
|
|
+ .ok_or(anyhow!("Can't parse alternative from: {s}"))?
|
|
|
.parse()
|
|
|
- .context(anyhow!("Error while parsing {}", row.reference))?,
|
|
|
- alternative: row
|
|
|
- .alt
|
|
|
+ .context(format!("Can't parse alternative from: {s}"))?,
|
|
|
+ quality: v
|
|
|
+ .get(5)
|
|
|
+ .map(|s| s.parse::<f32>().ok()) // Try to parse as f64; returns Option<f64>
|
|
|
+ .unwrap_or(None),
|
|
|
+ filter: v
|
|
|
+ .get(6)
|
|
|
+ .ok_or(anyhow!("Can't parse filter from: {s}"))?
|
|
|
.parse()
|
|
|
- .context(anyhow!("Error while parsing {}", row.alt))?,
|
|
|
- n_ref: None,
|
|
|
- n_alt: None,
|
|
|
- vaf: None,
|
|
|
- depth: None,
|
|
|
- callers_data,
|
|
|
- source: vec![source],
|
|
|
- variant_type,
|
|
|
+ .context(format!("Can't parse filter from: {s}"))?,
|
|
|
+ info: v
|
|
|
+ .get(7)
|
|
|
+ .ok_or(anyhow!("Can't parse id from: {s}"))?
|
|
|
+ .to_string(),
|
|
|
+ formats,
|
|
|
annotations: Vec::new(),
|
|
|
})
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- pub fn get_depth(&mut self) -> u32 {
|
|
|
- if let Some(depth) = self.depth {
|
|
|
- depth
|
|
|
- } else {
|
|
|
- let depth = self
|
|
|
- .callers_data
|
|
|
- .iter_mut()
|
|
|
- .map(|v| v.get_depth())
|
|
|
- .max()
|
|
|
- .unwrap();
|
|
|
- self.depth = Some(depth);
|
|
|
- depth
|
|
|
+// #CHROM POS ID REF ALT QUAL FILTER INFO FORMAT ADJAGBA_diag
|
|
|
+impl Variant {
|
|
|
+ pub fn into_vcf_row(&self) -> String {
|
|
|
+ let mut columns = vec![
|
|
|
+ self.contig.to_string(),
|
|
|
+ self.position.to_string(),
|
|
|
+ self.id.to_string(),
|
|
|
+ self.reference.to_string(),
|
|
|
+ self.alternative.to_string(),
|
|
|
+ self.quality
|
|
|
+ .map(|v| v.to_string())
|
|
|
+ .unwrap_or(".".to_string()),
|
|
|
+ self.filter.to_string(),
|
|
|
+ self.info.to_string(),
|
|
|
+ ];
|
|
|
+
|
|
|
+ if !self.formats.0.is_empty() {
|
|
|
+ let (format, values) = self.formats.clone().into();
|
|
|
+ columns.push(format);
|
|
|
+ columns.push(values);
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- pub fn get_n_alt(&mut self) -> u32 {
|
|
|
- if let Some(n_alt) = self.n_alt {
|
|
|
- n_alt
|
|
|
- } else {
|
|
|
- let n_alt = self
|
|
|
- .callers_data
|
|
|
- .iter_mut()
|
|
|
- .map(|v| v.get_n_alt())
|
|
|
- .max()
|
|
|
- .unwrap();
|
|
|
- self.n_alt = Some(n_alt);
|
|
|
- n_alt
|
|
|
- }
|
|
|
+ columns.join("\t")
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- pub fn vaf(&mut self) -> f32 {
|
|
|
- let n_alt = self.get_n_alt() as f32;
|
|
|
- let depth = self.get_depth() as f32;
|
|
|
- self.vaf = Some(n_alt / depth);
|
|
|
- self.vaf.unwrap()
|
|
|
- }
|
|
|
+// Tag
|
|
|
+#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
|
|
+pub enum Annotation {
|
|
|
+ Source(String),
|
|
|
+ Diag,
|
|
|
+ Constit,
|
|
|
+ Other((String, String)), // (key, value)
|
|
|
+}
|
|
|
|
|
|
- pub fn is_ins(&self) -> bool {
|
|
|
- matches!(
|
|
|
- (&self.reference, &self.alternative),
|
|
|
- (
|
|
|
- ReferenceAlternative::Nucleotide(_),
|
|
|
- ReferenceAlternative::Nucleotides(_)
|
|
|
- )
|
|
|
- )
|
|
|
- }
|
|
|
+/// Format
|
|
|
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
|
+pub enum Format {
|
|
|
+ GT(String),
|
|
|
+ GQ(u32),
|
|
|
+ DP(u32),
|
|
|
+ AD(Vec<u32>),
|
|
|
+ VAF(f32),
|
|
|
+ PL(Vec<u32>),
|
|
|
+ Other((String, String)), // (key, value)
|
|
|
+}
|
|
|
|
|
|
- pub fn alteration_category(&self) -> AlterationCategory {
|
|
|
- match (&self.reference, &self.alternative) {
|
|
|
- (ReferenceAlternative::Nucleotide(_), ReferenceAlternative::Nucleotide(_)) => {
|
|
|
- AlterationCategory::Snv
|
|
|
- }
|
|
|
- (ReferenceAlternative::Nucleotide(_), ReferenceAlternative::Nucleotides(_)) => {
|
|
|
- AlterationCategory::Ins
|
|
|
- }
|
|
|
- (ReferenceAlternative::Nucleotide(_), ReferenceAlternative::Unstructured(_)) => {
|
|
|
- AlterationCategory::Other
|
|
|
- }
|
|
|
- (ReferenceAlternative::Nucleotides(_), ReferenceAlternative::Nucleotide(_)) => {
|
|
|
- AlterationCategory::Del
|
|
|
- }
|
|
|
- (ReferenceAlternative::Nucleotides(a), ReferenceAlternative::Nucleotides(b))
|
|
|
- if a.len() < b.len() =>
|
|
|
- {
|
|
|
- AlterationCategory::Ins
|
|
|
- }
|
|
|
- (ReferenceAlternative::Nucleotides(a), ReferenceAlternative::Nucleotides(b))
|
|
|
- if a.len() > b.len() =>
|
|
|
- {
|
|
|
- AlterationCategory::Del
|
|
|
- }
|
|
|
- (ReferenceAlternative::Nucleotides(_), ReferenceAlternative::Nucleotides(_)) => {
|
|
|
- AlterationCategory::Rep
|
|
|
- }
|
|
|
- (ReferenceAlternative::Nucleotides(_), ReferenceAlternative::Unstructured(_)) => {
|
|
|
- AlterationCategory::Other
|
|
|
- }
|
|
|
- (ReferenceAlternative::Unstructured(_), ReferenceAlternative::Nucleotide(_)) => {
|
|
|
- AlterationCategory::Other
|
|
|
- }
|
|
|
- (ReferenceAlternative::Unstructured(_), ReferenceAlternative::Nucleotides(_)) => {
|
|
|
- AlterationCategory::Other
|
|
|
- }
|
|
|
- (ReferenceAlternative::Unstructured(_), ReferenceAlternative::Unstructured(_)) => {
|
|
|
- AlterationCategory::Other
|
|
|
- }
|
|
|
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
|
|
+pub struct Formats(Vec<Format>);
|
|
|
+
|
|
|
+impl TryFrom<(&str, &str)> for Formats {
|
|
|
+ type Error = anyhow::Error;
|
|
|
+
|
|
|
+ fn try_from((k, v): (&str, &str)) -> anyhow::Result<Self> {
|
|
|
+ let keys: Vec<&str> = k.split(':').collect();
|
|
|
+ let values: Vec<&str> = v.split(':').collect();
|
|
|
+
|
|
|
+ if keys.len() != values.len() {
|
|
|
+ anyhow::bail!("Mismatch between keys and values count for {k} {v}");
|
|
|
}
|
|
|
+
|
|
|
+ Ok(Self(
|
|
|
+ keys.into_iter()
|
|
|
+ .zip(values)
|
|
|
+ .map(|(key, value)| Format::try_from((key, value)))
|
|
|
+ .collect::<Result<Vec<Format>, _>>()
|
|
|
+ .map_err(|e| anyhow::anyhow!("Failed to parse format: {e}"))?,
|
|
|
+ ))
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- pub fn to_min_string(&mut self) -> String {
|
|
|
- let depth = self.get_depth();
|
|
|
- let n_alt = self.get_n_alt();
|
|
|
+impl From<Formats> for (String, String) {
|
|
|
+ fn from(formats: Formats) -> Self {
|
|
|
+ let mut keys = Vec::new();
|
|
|
+ let mut values = Vec::new();
|
|
|
|
|
|
- format!(
|
|
|
- "DP:AD\t{}:{}",
|
|
|
- depth,
|
|
|
- [(depth - n_alt).to_string(), n_alt.to_string()].join(",")
|
|
|
- )
|
|
|
- }
|
|
|
+ for format in formats.0 {
|
|
|
+ let (key, value): (String, String) = format.into();
|
|
|
+ keys.push(key);
|
|
|
+ values.push(value);
|
|
|
+ }
|
|
|
|
|
|
- pub fn get_veps(&self) -> Vec<VEP> {
|
|
|
- self.annotations
|
|
|
- .iter()
|
|
|
- .flat_map(|e| {
|
|
|
- if let AnnotationType::VEP(e) = e {
|
|
|
- e.clone()
|
|
|
- } else {
|
|
|
- vec![]
|
|
|
- }
|
|
|
- })
|
|
|
- .collect()
|
|
|
+ (keys.join(":"), values.join(":"))
|
|
|
}
|
|
|
- pub fn get_best_vep(&self) -> Result<VEP> {
|
|
|
- get_best_vep(&self.get_veps())
|
|
|
+}
|
|
|
+
|
|
|
+impl TryFrom<(&str, &str)> for Format {
|
|
|
+ type Error = anyhow::Error;
|
|
|
+
|
|
|
+ fn try_from((key, value): (&str, &str)) -> anyhow::Result<Self> {
|
|
|
+ Ok(match key {
|
|
|
+ "GT" => Format::GT(value.to_string()),
|
|
|
+ "GQ" => Format::GQ(value.parse().context(format!("Can't parse GQ: {value}"))?),
|
|
|
+ "DP" => Format::DP(value.parse().context(format!("Can't parse DP: {value}"))?),
|
|
|
+ "AD" => Format::AD(
|
|
|
+ value
|
|
|
+ .split(',')
|
|
|
+ .map(|e| e.parse().context("Failed to parse AD"))
|
|
|
+ .collect::<anyhow::Result<Vec<_>>>()?,
|
|
|
+ ),
|
|
|
+ "VAF" => Format::VAF(value.parse().context(format!("Can't parse VAF: {value}"))?),
|
|
|
+ "PL" => Format::PL(
|
|
|
+ value
|
|
|
+ .split(',')
|
|
|
+ .map(|e| e.parse().context("Failed to parse AD"))
|
|
|
+ .collect::<anyhow::Result<Vec<_>>>()?,
|
|
|
+ ),
|
|
|
+ _ => Format::Other((key.to_string(), value.to_string())),
|
|
|
+ })
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- pub fn is_from_category(&self, and_categories: &[Category]) -> bool {
|
|
|
- let mut vec_bools = Vec::new();
|
|
|
- for category in and_categories.iter() {
|
|
|
- match category {
|
|
|
- Category::VariantCategory(vc) => {
|
|
|
- for annotations in self.annotations.iter() {
|
|
|
- if let AnnotationType::VariantCategory(vvc) = annotations {
|
|
|
- if vc == vvc {
|
|
|
- vec_bools.push(true);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- Category::PositionRange { contig, from, to } => {
|
|
|
- if self.contig == *contig {
|
|
|
- match (from, to) {
|
|
|
- (None, None) => vec_bools.push(true),
|
|
|
- (None, Some(to)) => vec_bools.push(self.position <= *to),
|
|
|
- (Some(from), None) => vec_bools.push(self.position >= *from),
|
|
|
- (Some(from), Some(to)) => {
|
|
|
- vec_bools.push(self.position >= *from && self.position <= *to)
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- vec_bools.push(false);
|
|
|
- }
|
|
|
- }
|
|
|
- Category::VCFSource(_) => (),
|
|
|
- Category::NCosmic(n) => {
|
|
|
- let mut bools = Vec::new();
|
|
|
- for annotations in self.annotations.iter() {
|
|
|
- if let AnnotationType::Cosmic(c) = annotations {
|
|
|
- bools.push(c.cosmic_cnt >= *n);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- vec_bools.push(bools.iter().any(|&b| b));
|
|
|
- }
|
|
|
- Category::NCBIFeature(ncbi_feature) => {
|
|
|
- let mut bools = Vec::new();
|
|
|
- for annotations in self.annotations.iter() {
|
|
|
- if let AnnotationType::NCBIGFF(v) = annotations {
|
|
|
- bools.push(v.feature == *ncbi_feature);
|
|
|
- }
|
|
|
- }
|
|
|
- vec_bools.push(bools.iter().any(|&b| b));
|
|
|
- }
|
|
|
- Category::VAF { min, max } => {
|
|
|
- let v = if self.vaf.is_none() {
|
|
|
- let mut s = self.clone();
|
|
|
- s.vaf()
|
|
|
- } else {
|
|
|
- self.vaf.unwrap()
|
|
|
- };
|
|
|
- vec_bools.push(v >= *min && v <= *max);
|
|
|
- }
|
|
|
- Category::Pangolin => {
|
|
|
- vec_bools.push(
|
|
|
- self.annotations
|
|
|
- .iter()
|
|
|
- .filter(|a| matches!(a, AnnotationType::Pangolin(_)))
|
|
|
- .count()
|
|
|
- > 0,
|
|
|
- );
|
|
|
- }
|
|
|
+impl From<Format> for (String, String) {
|
|
|
+ fn from(format: Format) -> Self {
|
|
|
+ match format {
|
|
|
+ Format::GT(value) => ("GT".to_string(), value),
|
|
|
+ Format::GQ(value) => ("GQ".to_string(), value.to_string()),
|
|
|
+ Format::DP(value) => ("DP".to_string(), value.to_string()),
|
|
|
+ Format::AD(values) => {
|
|
|
+ let value_str = values
|
|
|
+ .iter()
|
|
|
+ .map(|v| v.to_string())
|
|
|
+ .collect::<Vec<_>>()
|
|
|
+ .join(",");
|
|
|
+ ("AD".to_string(), value_str)
|
|
|
+ }
|
|
|
+ Format::VAF(value) => ("VAF".to_string(), value.to_string()),
|
|
|
+ Format::PL(values) => {
|
|
|
+ let value_str = values
|
|
|
+ .iter()
|
|
|
+ .map(|v| v.to_string())
|
|
|
+ .collect::<Vec<_>>()
|
|
|
+ .join(",");
|
|
|
+ ("PL".to_string(), value_str)
|
|
|
}
|
|
|
+ Format::Other((key, value)) => (key, value),
|
|
|
}
|
|
|
- vec_bools.iter().all(|&x| x)
|
|
|
- }
|
|
|
-
|
|
|
- pub fn callers(&self) -> Vec<String> {
|
|
|
- self.source
|
|
|
- .iter()
|
|
|
- .map(|source| source.to_string())
|
|
|
- .collect()
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+/// Filter
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
|
|
-pub enum AlterationCategory {
|
|
|
- Snv,
|
|
|
- Ins,
|
|
|
- Del,
|
|
|
- Rep,
|
|
|
- Other,
|
|
|
+pub enum Filter {
|
|
|
+ PASS,
|
|
|
+ Other(String),
|
|
|
}
|
|
|
|
|
|
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)]
|
|
|
-pub enum AnnotationType {
|
|
|
- VariantCategory(VariantCategory),
|
|
|
- VEP(Vec<VEP>),
|
|
|
- Cluster(i32),
|
|
|
- Cosmic(Cosmic),
|
|
|
- GnomAD(GnomAD),
|
|
|
- NCBIGFF(NCBIGFF),
|
|
|
- Pangolin(Pangolin),
|
|
|
- Phase(PhaseAnnotation),
|
|
|
+impl FromStr for Filter {
|
|
|
+ type Err = anyhow::Error;
|
|
|
+
|
|
|
+ fn from_str(s: &str) -> anyhow::Result<Self> {
|
|
|
+ match s {
|
|
|
+ "PASS" => Ok(Filter::PASS),
|
|
|
+ _ => Ok(Filter::Other(s.to_string())),
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)]
|
|
|
-pub enum VariantCategory {
|
|
|
- Somatic,
|
|
|
- LowMRDDepth,
|
|
|
- LOH,
|
|
|
- Constit,
|
|
|
- LowDiversity,
|
|
|
+impl fmt::Display for Filter {
|
|
|
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
+ match self {
|
|
|
+ Filter::PASS => write!(f, "PASS"),
|
|
|
+ Filter::Other(ref s) => write!(f, "{}", s),
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, ToSchema)]
|
|
|
+#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
|
|
pub enum ReferenceAlternative {
|
|
|
Nucleotide(Base),
|
|
|
Nucleotides(Vec<Base>),
|
|
|
@@ -280,7 +264,7 @@ pub enum ReferenceAlternative {
|
|
|
impl FromStr for ReferenceAlternative {
|
|
|
type Err = anyhow::Error;
|
|
|
|
|
|
- fn from_str(s: &str) -> Result<Self> {
|
|
|
+ fn from_str(s: &str) -> anyhow::Result<Self> {
|
|
|
let possible_bases = s.as_bytes().iter();
|
|
|
let mut res: Vec<Base> = Vec::new();
|
|
|
for &base in possible_bases {
|
|
|
@@ -313,7 +297,7 @@ impl fmt::Display for ReferenceAlternative {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, ToSchema)]
|
|
|
+#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
|
|
pub enum Base {
|
|
|
A,
|
|
|
T,
|
|
|
@@ -324,14 +308,14 @@ pub enum Base {
|
|
|
|
|
|
impl TryFrom<u8> for Base {
|
|
|
type Error = anyhow::Error;
|
|
|
- fn try_from(base: u8) -> Result<Self> {
|
|
|
+ fn try_from(base: u8) -> anyhow::Result<Self> {
|
|
|
match base {
|
|
|
b'A' => Ok(Base::A),
|
|
|
b'T' => Ok(Base::T),
|
|
|
b'C' => Ok(Base::C),
|
|
|
b'G' => Ok(Base::G),
|
|
|
b'N' => Ok(Base::N),
|
|
|
- _ => Err(anyhow!(
|
|
|
+ _ => Err(anyhow::anyhow!(
|
|
|
"Unknown base: {}",
|
|
|
String::from_utf8_lossy(&[base])
|
|
|
)),
|
|
|
@@ -365,43 +349,6 @@ impl fmt::Display for Base {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ToSchema)]
|
|
|
-pub enum Format {
|
|
|
- DeepVariant(DeepVariantFormat),
|
|
|
- ClairS(ClairSFormat),
|
|
|
- Sniffles(SnifflesFormat),
|
|
|
- Nanomonsv(NanomonsvFormat),
|
|
|
-}
|
|
|
-
|
|
|
-#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ToSchema)]
|
|
|
-pub enum Info {
|
|
|
- #[schema(value_type=String)]
|
|
|
- DeepVariant(DeepVariantInfo),
|
|
|
- #[schema(value_type=String)]
|
|
|
- ClairS(ClairSInfo),
|
|
|
- #[schema(value_type=String)]
|
|
|
- Sniffles(SnifflesInfo),
|
|
|
- #[schema(value_type=String)]
|
|
|
- Nanomonsv(NanomonsvInfo),
|
|
|
-}
|
|
|
-
|
|
|
-fn parse_info(s: &str, source: &VCFSource) -> Result<Info> {
|
|
|
- match source {
|
|
|
- VCFSource::DeepVariant => Ok(Info::DeepVariant(s.parse()?)),
|
|
|
- VCFSource::ClairS => Ok(Info::ClairS(s.parse()?)),
|
|
|
- VCFSource::Sniffles => Ok(Info::Sniffles(s.parse()?)),
|
|
|
- VCFSource::Nanomonsv => Ok(Info::Nanomonsv(s.parse()?)),
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-fn parse_format(vcf_source: &VCFSource, data: &str) -> Result<Format> {
|
|
|
- let res = match vcf_source {
|
|
|
- VCFSource::DeepVariant => Format::DeepVariant(data.parse()?),
|
|
|
- VCFSource::ClairS => Format::ClairS(data.parse()?),
|
|
|
- VCFSource::Sniffles => Format::Sniffles(data.parse()?),
|
|
|
- VCFSource::Nanomonsv => Format::Nanomonsv(data.parse()?),
|
|
|
- };
|
|
|
- Ok(res)
|
|
|
+pub trait Variants {
|
|
|
+ fn variants(&self) -> anyhow::Result<Vec<Variant>>;
|
|
|
}
|
|
|
-
|
|
|
-
|