1use std::fmt;
2
3use use_chemical_formula::ChemicalFormula;
4
5use crate::{
6 CommonName, CompoundFormula, CompoundIdentifier, CompoundKind, CompoundName,
7 CompoundValidationError, EmpiricalFormula, MolecularFormula, SystematicName,
8};
9
10#[derive(Clone, Debug, Eq, PartialEq)]
12pub struct Compound {
13 name: CompoundName,
14 formula: CompoundFormula,
15 common_name: Option<CommonName>,
16 systematic_name: Option<SystematicName>,
17 empirical_formula: Option<EmpiricalFormula>,
18 molecular_formula: Option<MolecularFormula>,
19 kinds: Vec<CompoundKind>,
20 identifiers: Vec<CompoundIdentifier>,
21}
22
23impl Compound {
24 pub fn new(name: &str, formula: ChemicalFormula) -> Result<Self, CompoundValidationError> {
30 Ok(Self {
31 name: CompoundName::new(name)?,
32 formula: CompoundFormula::new(formula),
33 common_name: None,
34 systematic_name: None,
35 empirical_formula: None,
36 molecular_formula: None,
37 kinds: Vec::new(),
38 identifiers: Vec::new(),
39 })
40 }
41
42 #[must_use]
44 pub const fn name(&self) -> &CompoundName {
45 &self.name
46 }
47
48 #[must_use]
50 pub fn formula(&self) -> &ChemicalFormula {
51 self.formula.as_formula()
52 }
53
54 #[must_use]
56 pub const fn compound_formula(&self) -> &CompoundFormula {
57 &self.formula
58 }
59
60 #[must_use]
62 pub const fn common_name(&self) -> Option<&CommonName> {
63 self.common_name.as_ref()
64 }
65
66 #[must_use]
68 pub const fn systematic_name(&self) -> Option<&SystematicName> {
69 self.systematic_name.as_ref()
70 }
71
72 #[must_use]
74 pub const fn empirical_formula(&self) -> Option<&EmpiricalFormula> {
75 self.empirical_formula.as_ref()
76 }
77
78 #[must_use]
80 pub const fn molecular_formula(&self) -> Option<&MolecularFormula> {
81 self.molecular_formula.as_ref()
82 }
83
84 #[must_use]
86 pub fn kinds(&self) -> &[CompoundKind] {
87 &self.kinds
88 }
89
90 #[must_use]
92 pub fn identifiers(&self) -> &[CompoundIdentifier] {
93 &self.identifiers
94 }
95
96 #[must_use]
98 pub fn with_kind(mut self, kind: CompoundKind) -> Self {
99 if !self.kinds.contains(&kind) {
100 self.kinds.push(kind);
101 }
102 self
103 }
104
105 #[must_use]
107 pub fn with_common_name(mut self, common_name: CommonName) -> Self {
108 self.common_name = Some(common_name);
109 self
110 }
111
112 pub fn try_with_common_name(self, common_name: &str) -> Result<Self, CompoundValidationError> {
118 Ok(self.with_common_name(CommonName::new(common_name)?))
119 }
120
121 #[must_use]
123 pub fn with_systematic_name(mut self, systematic_name: SystematicName) -> Self {
124 self.systematic_name = Some(systematic_name);
125 self
126 }
127
128 pub fn try_with_systematic_name(
134 self,
135 systematic_name: &str,
136 ) -> Result<Self, CompoundValidationError> {
137 Ok(self.with_systematic_name(SystematicName::new(systematic_name)?))
138 }
139
140 #[must_use]
142 pub fn with_empirical_formula(mut self, formula: EmpiricalFormula) -> Self {
143 self.empirical_formula = Some(formula);
144 self
145 }
146
147 #[must_use]
149 pub fn with_molecular_formula(mut self, formula: MolecularFormula) -> Self {
150 self.molecular_formula = Some(formula);
151 self
152 }
153
154 pub fn try_with_identifier(
161 mut self,
162 identifier: CompoundIdentifier,
163 ) -> Result<Self, CompoundValidationError> {
164 if !self.identifiers.contains(&identifier) {
165 self.identifiers.push(identifier);
166 }
167 Ok(self)
168 }
169}
170
171impl fmt::Display for Compound {
172 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
173 write!(formatter, "{} ({})", self.name, self.formula)
174 }
175}