1use crate::*;
2use indexmap::map::*;
3
4#[cfg(feature = "record")]
7#[derive(Clone, Debug, PartialEq, Eq)]
8pub struct MechRecord {
9 pub cols: usize,
10 pub kinds: Vec<ValueKind>,
11 pub data: IndexMap<u64,Value>,
12 pub field_names: HashMap<u64,String>,
13}
14
15#[cfg(feature = "record")]
16impl MechRecord {
17
18 pub fn check_record_schema(&self, record: &MechRecord) -> MResult<()> {
19 for (&field_id, _value) in &self.data {
20 if !record.data.contains_key(&field_id) {
22 return Err(MechError2::new(MissingFieldInRecordError { field_id }, None).with_compiler_loc());
23 }
24 let expected_kind = self.kinds.get(self.key_index(field_id)?)
26 .ok_or_else(|| MechError2::new(MissingKindForFieldError { field_id }, None).with_compiler_loc())?;
27 let actual_kind = record.kinds.get(record.key_index(field_id)?)
29 .ok_or_else(|| MechError2::new(MissingKindInComparedRecordError { field_id }, None).with_compiler_loc())?;
30 if expected_kind != actual_kind {
32 return Err(MechError2::new(
33 RecordFieldKindMismatchError {
34 field_id,
35 expected_kind: expected_kind.clone(),
36 actual_kind: actual_kind.clone(),
37 },
38 None
39 ).with_compiler_loc());
40 }
41 if self.field_names.get(&field_id) != record.field_names.get(&field_id) {
43 return Err(MechError2::new(
44 RecordFieldNameMismatchError {
45 field_id,
46 expected_name: self.field_names.get(&field_id).cloned(),
47 actual_name: record.field_names.get(&field_id).cloned(),
48 },
49 None
50 ).with_compiler_loc());
51 }
52 }
53 Ok(())
54 }
55
56 fn key_index(&self, field_id: u64) -> MResult<usize> {
57 self.data.keys().position(|&id| id == field_id).ok_or_else(|| {
58 MechError2::new(
59 KeyNotFoundInKeyIndexError { field_id },
60 None
61 ).with_compiler_loc()
62 })
63 }
64
65 #[cfg(feature = "pretty_print")]
66 pub fn to_html(&self) -> String {
67 let mut bindings = Vec::new();
68
69 for (key, value) in &self.data {
70 let name = self.field_names.get(key).unwrap();
71
72 let binding_html = format!(
73 "<span class=\"mech-binding\">\
74 <span class=\"mech-binding-name\">{}</span>\
75 <span class=\"mech-binding-colon-op\">:</span>\
76 <span class=\"mech-binding-value\">{}</span>\
77 </span>",
78 name,
79 value.to_html(),
80 );
81
82 bindings.push(binding_html);
83 }
84
85 format!(
86 "<span class=\"mech-record\">\
87 <span class=\"mech-start-brace\">{{</span>{}<span class=\"mech-end-brace\">}}</span>\
88 </span>",
89 bindings.join("<span class=\"mech-separator\">, </span>")
90 )
91 }
92
93 pub fn get(&self, key: &u64) -> Option<&Value> {
94 self.data.get(key)
95 }
96
97 pub fn new(vec: Vec<(&str, Value)>) -> MechRecord {
98 let mut data = IndexMap::new();
99 let mut field_names = HashMap::new();
100
101 for (name, value) in vec {
102 let col_id = hash_str(name);
103
104 field_names.insert(col_id, name.to_string());
105 data.insert(col_id, value);
106 }
107
108 let kinds = data.iter().map(|(_, v)| v.kind()).collect();
109
110 MechRecord {
111 cols: data.len(),
112 kinds,
113 data,
114 field_names,
115 }
116 }
117
118 pub fn from_vec(vec: Vec<((u64,String),Value)>) -> MechRecord {
119 let mut data = IndexMap::new();
120 let mut field_names = HashMap::new();
121 for ((k,s),v) in vec {
122 field_names.insert(k,s);
123 data.insert(k,v);
124 }
125 let kinds = data.iter().map(|(_,v)| v.kind()).collect();
126 MechRecord{cols: data.len(), kinds, data, field_names}
127 }
128
129 pub fn from_kind(fields: &Vec<(String,ValueKind)>) -> MResult<MechRecord> {
130 let mut data = IndexMap::new();
131 let mut field_names = HashMap::new();
132 for (name, knd) in fields {
133 let col_id = hash_str(name);
134 field_names.insert(col_id, name.to_string());
135 data.insert(col_id, Value::from_kind(knd));
136 }
137 let kinds = data.iter().map(|(_,v)| v.kind()).collect();
138 Ok(MechRecord{cols: data.len(), kinds, data, field_names})
139 }
140
141 pub fn insert_field(&mut self, key: u64, value: Value) {
142 self.cols += 1;
143 self.kinds.push(value.kind());
144 self.data.insert(key, value);
145 }
146
147 pub fn kind(&self) -> ValueKind {
148 ValueKind::Record(self.data.iter()
149 .map(|(k,v)| (self.field_names.get(k).unwrap().to_string(), v.kind()))
150 .collect())
151 }
152
153 pub fn size_of(&self) -> usize {
154 self.data.iter().map(|(_,v)| v.size_of()).sum()
155 }
156
157 pub fn shape(&self) -> Vec<usize> {
158 vec![1,self.cols]
159 }
160}
161
162#[cfg(feature = "pretty_print")]
163impl PrettyPrint for MechRecord {
164 fn pretty_print(&self) -> String {
165 let mut lines = Vec::new();
166
167 for (k, v) in &self.data {
168 let field_name = self.field_names.get(k).unwrap();
169 lines.push(format!(
170 " {}<{}>: {}",
171 field_name,
172 v.kind(),
173 v.pretty_print()
174 ));
175 }
176
177 format!("{{\n{}\n}}", lines.join("\n"))
178 }
179}
180
181#[cfg(feature = "record")]
182impl Hash for MechRecord {
183 fn hash<H: Hasher>(&self, state: &mut H) {
184 for (k,v) in self.data.iter() {
185 k.hash(state);
186 v.hash(state);
187 }
188 }
189}
190
191#[derive(Debug, Clone)]
192pub struct MissingFieldInRecordError {
193 pub field_id: u64,
194}
195
196impl MechErrorKind2 for MissingFieldInRecordError {
197 fn name(&self) -> &str {
198 "MissingFieldInRecord"
199 }
200 fn message(&self) -> String {
201 format!("Record is missing required field `{}`.", self.field_id)
202 }
203}
204
205#[derive(Debug, Clone)]
206pub struct MissingKindForFieldError {
207 pub field_id: u64,
208}
209
210impl MechErrorKind2 for MissingKindForFieldError {
211 fn name(&self) -> &str {
212 "MissingKindForField"
213 }
214 fn message(&self) -> String {
215 format!("Missing expected kind for field `{}` in schema.", self.field_id)
216 }
217}
218
219#[derive(Debug, Clone)]
220pub struct MissingKindInComparedRecordError {
221 pub field_id: u64,
222}
223
224impl MechErrorKind2 for MissingKindInComparedRecordError {
225 fn name(&self) -> &str {
226 "MissingKindInComparedRecord"
227 }
228 fn message(&self) -> String {
229 format!("Missing kind for field `{}` in the compared record.", self.field_id)
230 }
231}
232
233#[derive(Debug, Clone)]
234pub struct RecordFieldKindMismatchError {
235 pub field_id: u64,
236 pub expected_kind: ValueKind,
237 pub actual_kind: ValueKind,
238}
239
240impl MechErrorKind2 for RecordFieldKindMismatchError {
241 fn name(&self) -> &str {
242 "RecordFieldKindMismatch"
243 }
244 fn message(&self) -> String {
245 format!(
246 "Kind mismatch for column `{}` (expected `{}`, found `{}`).",
247 self.field_id, self.expected_kind, self.actual_kind
248 )
249 }
250}
251
252#[derive(Debug, Clone)]
253pub struct RecordFieldNameMismatchError {
254 pub field_id: u64,
255 pub expected_name: Option<String>,
256 pub actual_name: Option<String>,
257}
258
259impl MechErrorKind2 for RecordFieldNameMismatchError {
260 fn name(&self) -> &str {
261 "RecordFieldNameMismatch"
262 }
263 fn message(&self) -> String {
264 match (&self.expected_name, &self.actual_name) {
265 (Some(e), Some(a)) => format!(
266 "Field name mismatch for field `{}` (expected `{}`, found `{}`).",
267 self.field_id, e, a
268 ),
269 (Some(e), None) => format!(
270 "Field name mismatch for field `{}` (expected `{}`, but no field found).",
271 self.field_id, e
272 ),
273 _ => format!("Field name mismatch for field `{}`.", self.field_id),
274 }
275 }
276}
277
278#[derive(Debug, Clone)]
279pub struct KeyNotFoundInKeyIndexError {
280 pub field_id: u64,
281}
282
283impl MechErrorKind2 for KeyNotFoundInKeyIndexError {
284 fn name(&self) -> &str {
285 "KeyNotFoundInKeyIndex"
286 }
287 fn message(&self) -> String {
288 format!("Key id `{}` not found in key_index.", self.field_id)
289 }
290}