use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
pub enum SemanticType {
Disease,
Finding,
Procedure,
Substance,
Pharmaceutical,
Gene,
Variant,
Anatomical,
Observable,
Specimen,
BodyStructure,
Event,
Environment,
SocialConcept,
Stated,
Group,
#[serde(other)]
#[default]
Unknown,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SnomedConcept {
pub id: u64,
pub term: String,
#[serde(alias = "semantic")]
pub semantic_type: SemanticType,
#[serde(default)]
pub synonyms: Vec<String>,
#[serde(default)]
pub parents: Vec<u64>,
}
impl SnomedConcept {
pub fn new(id: u64, term: String, semantic_type: SemanticType) -> Self {
Self {
id,
term,
semantic_type,
synonyms: Vec::new(),
parents: Vec::new(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SnomedMatch {
pub concept_id: u64,
pub term: String,
pub canonical: String,
pub semantic_type: SemanticType,
pub span: (usize, usize),
pub confidence: f32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SnomedSubset {
pub concepts: Vec<SnomedConcept>,
}
impl SnomedSubset {
pub fn from_json(data: &[u8]) -> anyhow::Result<Self> {
if let Ok(concepts) = serde_json::from_slice::<Vec<SnomedConcept>>(data) {
return Ok(Self { concepts });
}
Ok(serde_json::from_slice(data)?)
}
}
pub fn create_concept_index(concepts: &[SnomedConcept]) -> HashMap<u64, SnomedConcept> {
concepts.iter().map(|c| (c.id, c.clone())).collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_semantic_type_parse() {
let json = r#"{"semantic": "Disease"}"#;
let parsed: serde_json::Value = serde_json::from_str(json).unwrap();
let st = serde_json::from_value::<SemanticType>(parsed.get("semantic").unwrap().clone());
assert!(st.is_ok());
assert_eq!(st.unwrap(), SemanticType::Disease);
}
#[test]
fn test_snomed_subset_parsing() {
let data = r#"[
{"id": 254637007, "term": "NSCLC", "semantic": "Disease"},
{"id": 363358000, "term": "EGFR", "semantic": "Gene"}
]"#;
let subset = SnomedSubset::from_json(data.as_bytes());
assert!(subset.is_ok());
assert_eq!(subset.unwrap().concepts.len(), 2);
}
}