feos_core/parameter/
identifier.rs

1use serde::{Deserialize, Serialize};
2use std::hash::{Hash, Hasher};
3
4/// Possible variants to identify a substance.
5#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
6#[cfg_attr(feature = "python", pyo3::pyclass(eq))]
7pub enum IdentifierOption {
8    Cas,
9    Name,
10    IupacName,
11    Smiles,
12    Inchi,
13    Formula,
14}
15
16/// A collection of identifiers for a chemical structure or substance.
17#[derive(Serialize, Deserialize, Debug, Clone, Default)]
18pub struct Identifier {
19    /// CAS number
20    #[serde(default)]
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub cas: Option<String>,
23    /// Commonly used english name
24    #[serde(default)]
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub name: Option<String>,
27    /// IUPAC name
28    #[serde(default)]
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub iupac_name: Option<String>,
31    /// SMILES key
32    #[serde(default)]
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub smiles: Option<String>,
35    /// InchI key
36    #[serde(default)]
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub inchi: Option<String>,
39    /// Chemical formula
40    #[serde(default)]
41    #[serde(skip_serializing_if = "Option::is_none")]
42    pub formula: Option<String>,
43}
44
45impl Identifier {
46    /// Create a new identifier.
47    ///
48    /// # Examples
49    ///
50    /// ```no_run
51    /// # use feos_core::parameter::Identifier;
52    /// let methanol = Identifier::new(
53    ///     Some("67-56-1"),
54    ///     Some("methanol"),
55    ///     Some("methanol"),
56    ///     Some("CO"),
57    ///     Some("InChI=1S/CH4O/c1-2/h2H,1H3"),
58    ///     Some("CH4O")
59    /// );
60    pub fn new(
61        cas: Option<&str>,
62        name: Option<&str>,
63        iupac_name: Option<&str>,
64        smiles: Option<&str>,
65        inchi: Option<&str>,
66        formula: Option<&str>,
67    ) -> Identifier {
68        Identifier {
69            cas: cas.map(Into::into),
70            name: name.map(Into::into),
71            iupac_name: iupac_name.map(Into::into),
72            smiles: smiles.map(Into::into),
73            inchi: inchi.map(Into::into),
74            formula: formula.map(Into::into),
75        }
76    }
77
78    pub fn as_string(&self, option: IdentifierOption) -> Option<String> {
79        match option {
80            IdentifierOption::Cas => self.cas.clone(),
81            IdentifierOption::Name => self.name.clone(),
82            IdentifierOption::IupacName => self.iupac_name.clone(),
83            IdentifierOption::Smiles => self.smiles.clone(),
84            IdentifierOption::Inchi => self.inchi.clone(),
85            IdentifierOption::Formula => self.formula.clone(),
86        }
87    }
88}
89
90impl std::fmt::Display for Identifier {
91    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92        let mut ids = Vec::new();
93        if let Some(n) = &self.cas {
94            ids.push(format!("cas={}", n));
95        }
96        if let Some(n) = &self.name {
97            ids.push(format!("name={}", n));
98        }
99        if let Some(n) = &self.iupac_name {
100            ids.push(format!("iupac_name={}", n));
101        }
102        if let Some(n) = &self.smiles {
103            ids.push(format!("smiles={}", n));
104        }
105        if let Some(n) = &self.inchi {
106            ids.push(format!("inchi={}", n));
107        }
108        if let Some(n) = &self.formula {
109            ids.push(format!("formula={}", n));
110        }
111        write!(f, "Identifier({})", ids.join(", "))
112    }
113}
114
115impl PartialEq for Identifier {
116    fn eq(&self, other: &Self) -> bool {
117        self.cas == other.cas
118    }
119}
120impl Eq for Identifier {}
121
122impl Hash for Identifier {
123    fn hash<H: Hasher>(&self, state: &mut H) {
124        self.cas.hash(state);
125    }
126}
127
128#[cfg(test)]
129mod test {
130    use super::*;
131
132    #[test]
133    fn test_fmt() {
134        let id = Identifier::new(None, Some("acetone"), None, Some("CC(=O)C"), None, None);
135        assert_eq!(id.to_string(), "Identifier(name=acetone, smiles=CC(=O)C)");
136    }
137}