feos_core/parameter/
identifier.rs1use serde::{Deserialize, Serialize};
2use std::fmt;
3use std::hash::{Hash, Hasher};
4
5#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
7pub enum IdentifierOption {
8 Cas,
9 Name,
10 IupacName,
11 Smiles,
12 Inchi,
13 Formula,
14}
15
16impl fmt::Display for IdentifierOption {
17 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18 let str = match self {
19 IdentifierOption::Cas => "CAS",
20 IdentifierOption::Name => "name",
21 IdentifierOption::IupacName => "IUPAC name",
22 IdentifierOption::Smiles => "SMILES",
23 IdentifierOption::Inchi => "InChI",
24 IdentifierOption::Formula => "formula",
25 };
26 write!(f, "{str}")
27 }
28}
29
30#[derive(Serialize, Deserialize, Debug, Clone, Default)]
32pub struct Identifier {
33 #[serde(default)]
35 #[serde(skip_serializing_if = "Option::is_none")]
36 pub cas: Option<String>,
37 #[serde(default)]
39 #[serde(skip_serializing_if = "Option::is_none")]
40 pub name: Option<String>,
41 #[serde(default)]
43 #[serde(skip_serializing_if = "Option::is_none")]
44 pub iupac_name: Option<String>,
45 #[serde(default)]
47 #[serde(skip_serializing_if = "Option::is_none")]
48 pub smiles: Option<String>,
49 #[serde(default)]
51 #[serde(skip_serializing_if = "Option::is_none")]
52 pub inchi: Option<String>,
53 #[serde(default)]
55 #[serde(skip_serializing_if = "Option::is_none")]
56 pub formula: Option<String>,
57}
58
59impl Identifier {
60 pub fn new(
75 cas: Option<&str>,
76 name: Option<&str>,
77 iupac_name: Option<&str>,
78 smiles: Option<&str>,
79 inchi: Option<&str>,
80 formula: Option<&str>,
81 ) -> Identifier {
82 Identifier {
83 cas: cas.map(Into::into),
84 name: name.map(Into::into),
85 iupac_name: iupac_name.map(Into::into),
86 smiles: smiles.map(Into::into),
87 inchi: inchi.map(Into::into),
88 formula: formula.map(Into::into),
89 }
90 }
91
92 pub fn as_str(&self, option: IdentifierOption) -> Option<&str> {
93 match option {
94 IdentifierOption::Cas => self.cas.as_deref(),
95 IdentifierOption::Name => self.name.as_deref(),
96 IdentifierOption::IupacName => self.iupac_name.as_deref(),
97 IdentifierOption::Smiles => self.smiles.as_deref(),
98 IdentifierOption::Inchi => self.inchi.as_deref(),
99 IdentifierOption::Formula => self.formula.as_deref(),
100 }
101 }
102
103 pub fn as_readable_str(&self) -> Option<&str> {
106 self.name
107 .as_deref()
108 .or(self.iupac_name.as_deref())
109 .or(self.smiles.as_deref())
110 .or(self.cas.as_deref())
111 .or(self.inchi.as_deref())
112 .or(self.formula.as_deref())
113 }
114}
115
116impl std::fmt::Display for Identifier {
117 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118 let mut ids = Vec::new();
119 if let Some(n) = &self.cas {
120 ids.push(format!("cas={n}"));
121 }
122 if let Some(n) = &self.name {
123 ids.push(format!("name={n}"));
124 }
125 if let Some(n) = &self.iupac_name {
126 ids.push(format!("iupac_name={n}"));
127 }
128 if let Some(n) = &self.smiles {
129 ids.push(format!("smiles={n}"));
130 }
131 if let Some(n) = &self.inchi {
132 ids.push(format!("inchi={n}"));
133 }
134 if let Some(n) = &self.formula {
135 ids.push(format!("formula={n}"));
136 }
137 write!(f, "Identifier({})", ids.join(", "))
138 }
139}
140
141impl PartialEq for Identifier {
142 fn eq(&self, other: &Self) -> bool {
143 self.cas == other.cas
144 }
145}
146impl Eq for Identifier {}
147
148impl Hash for Identifier {
149 fn hash<H: Hasher>(&self, state: &mut H) {
150 self.cas.hash(state);
151 }
152}
153
154#[cfg(test)]
155mod test {
156 use super::*;
157
158 #[test]
159 fn test_fmt() {
160 let id = Identifier::new(None, Some("acetone"), None, Some("CC(=O)C"), None, None);
161 assert_eq!(id.to_string(), "Identifier(name=acetone, smiles=CC(=O)C)");
162 }
163}