1use super::identifier::Identifier;
2use super::segment::SegmentRecord;
3use super::{IdentifierOption, ParameterError};
4use conv::ValueInto;
5use serde::de::DeserializeOwned;
6use serde::{Deserialize, Serialize};
7use std::collections::{HashMap, HashSet};
8use std::fs::File;
9use std::io::BufReader;
10use std::path::Path;
11
12#[derive(Serialize, Deserialize, Debug, Clone)]
14pub struct PureRecord<M> {
15 pub identifier: Identifier,
16 #[serde(default)]
17 pub molarweight: f64,
18 pub model_record: M,
19}
20
21impl<M> PureRecord<M> {
22 pub fn new(identifier: Identifier, molarweight: f64, model_record: M) -> Self {
24 Self {
25 identifier,
26 molarweight,
27 model_record,
28 }
29 }
30
31 pub fn from_segments<S, T>(identifier: Identifier, segments: S) -> Result<Self, ParameterError>
36 where
37 T: Copy + ValueInto<f64>,
38 M: FromSegments<T>,
39 S: IntoIterator<Item = (SegmentRecord<M>, T)>,
40 {
41 let mut molarweight = 0.0;
42 let mut model_segments = Vec::new();
43 for (s, n) in segments {
44 molarweight += s.molarweight * n.value_into().unwrap();
45 model_segments.push((s.model_record, n));
46 }
47 let model_record = M::from_segments(&model_segments)?;
48
49 Ok(Self::new(identifier, molarweight, model_record))
50 }
51
52 pub fn from_json<P>(
54 substances: &[&str],
55 file: P,
56 identifier_option: IdentifierOption,
57 ) -> Result<Vec<Self>, ParameterError>
58 where
59 P: AsRef<Path>,
60 M: Clone + DeserializeOwned,
61 {
62 let mut queried: HashSet<String> = substances.iter().map(|s| s.to_string()).collect();
64 if queried.len() != substances.len() {
66 return Err(ParameterError::IncompatibleParameters(
67 "A substance was defined more than once.".to_string(),
68 ));
69 }
70
71 let f = File::open(file)?;
72 let reader = BufReader::new(f);
73 let file_records: Vec<Self> = serde_json::from_reader(reader)?;
75 let mut records: HashMap<String, Self> = HashMap::with_capacity(substances.len());
76
77 for record in file_records {
79 if let Some(id) = record.identifier.as_string(identifier_option) {
80 queried.take(&id).map(|id| records.insert(id, record));
81 }
82 if queried.is_empty() {
84 break;
85 }
86 }
87
88 if !queried.is_empty() {
90 return Err(ParameterError::ComponentsNotFound(format!("{:?}", queried)));
91 };
92
93 Ok(substances
95 .iter()
96 .map(|&s| records.get(s).unwrap().clone())
97 .collect())
98 }
99}
100
101impl<M> std::fmt::Display for PureRecord<M>
102where
103 M: std::fmt::Display,
104{
105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106 write!(f, "PureRecord(")?;
107 write!(f, "\n\tidentifier={},", self.identifier)?;
108 write!(f, "\n\tmolarweight={},", self.molarweight)?;
109 write!(f, "\n\tmodel_record={},", self.model_record)?;
110 write!(f, "\n)")
111 }
112}
113
114pub trait FromSegments<T>: Clone {
117 fn from_segments(segments: &[(Self, T)]) -> Result<Self, ParameterError>;
120}
121
122pub trait FromSegmentsBinary<T>: Clone {
125 fn from_segments_binary(segments: &[(f64, T, T)]) -> Result<Self, ParameterError>;
128}
129
130#[derive(Serialize, Deserialize, Debug, Clone)]
133pub struct BinaryRecord<I, B> {
134 pub id1: I,
136 pub id2: I,
138 pub model_record: B,
140}
141
142impl<I, B> BinaryRecord<I, B> {
143 pub fn new(id1: I, id2: I, model_record: B) -> Self {
145 Self {
146 id1,
147 id2,
148 model_record,
149 }
150 }
151
152 pub fn from_json<P: AsRef<Path>>(file: P) -> Result<Vec<Self>, ParameterError>
154 where
155 I: DeserializeOwned,
156 B: DeserializeOwned,
157 {
158 Ok(serde_json::from_reader(BufReader::new(File::open(file)?))?)
159 }
160}
161
162impl<I, B> std::fmt::Display for BinaryRecord<I, B>
163where
164 I: std::fmt::Display,
165 B: std::fmt::Display,
166{
167 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
168 write!(f, "BinaryRecord(")?;
169 write!(f, "\n\tid1={},", self.id1)?;
170 write!(f, "\n\tid2={},", self.id2)?;
171 write!(f, "\n\tmodel_record={},", self.model_record)?;
172 write!(f, "\n)")
173 }
174}
175
176#[cfg(test)]
177mod test {
178 use super::*;
179
180 #[derive(Serialize, Deserialize, Debug, Default, Clone)]
181 struct TestModelRecordSegments {
182 a: f64,
183 }
184
185 #[test]
186 fn deserialize() {
187 let r = r#"
188 {
189 "identifier": {
190 "cas": "123-4-5"
191 },
192 "molarweight": 16.0426,
193 "model_record": {
194 "a": 0.1
195 }
196 }
197 "#;
198 let record: PureRecord<TestModelRecordSegments> =
199 serde_json::from_str(r).expect("Unable to parse json.");
200 assert_eq!(record.identifier.cas, Some("123-4-5".into()))
201 }
202
203 #[test]
204 fn deserialize_list() {
205 let r = r#"
206 [
207 {
208 "identifier": {
209 "cas": "1"
210 },
211 "molarweight": 1.0,
212 "model_record": {
213 "a": 1.0
214 }
215 },
216 {
217 "identifier": {
218 "cas": "2"
219 },
220 "molarweight": 2.0,
221 "model_record": {
222 "a": 2.0
223 }
224 }
225 ]"#;
226 let records: Vec<PureRecord<TestModelRecordSegments>> =
227 serde_json::from_str(r).expect("Unable to parse json.");
228 assert_eq!(records[0].identifier.cas, Some("1".into()));
229 assert_eq!(records[1].identifier.cas, Some("2".into()))
230 }
231}