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 insert_field(&mut self, key: u64, value: Value) {
130 self.cols += 1;
131 self.kinds.push(value.kind());
132 self.data.insert(key, value);
133 }
134
135 pub fn kind(&self) -> ValueKind {
136 ValueKind::Record(self.data.iter()
137 .map(|(k,v)| (self.field_names.get(k).unwrap().to_string(), v.kind()))
138 .collect())
139 }
140
141 pub fn size_of(&self) -> usize {
142 self.data.iter().map(|(_,v)| v.size_of()).sum()
143 }
144
145 pub fn shape(&self) -> Vec<usize> {
146 vec![1,self.cols]
147 }
148}
149
150#[cfg(feature = "pretty_print")]
151impl PrettyPrint for MechRecord {
152 fn pretty_print(&self) -> String {
153 let mut builder = Builder::default();
154 let mut key_strings = vec![];
155 let mut element_strings = vec![];
156 for (k,v) in &self.data {
157 let field_name = self.field_names.get(k).unwrap();
158 key_strings.push(format!("{}<{}>",field_name, v.kind()));
159 element_strings.push(v.pretty_print());
160 }
161 builder.push_record(key_strings);
162 builder.push_record(element_strings);
163 let mut table = builder.build();
164 table.with(Style::modern_rounded());
165 format!("{table}")
166 }
167}
168
169#[cfg(feature = "record")]
170impl Hash for MechRecord {
171 fn hash<H: Hasher>(&self, state: &mut H) {
172 for (k,v) in self.data.iter() {
173 k.hash(state);
174 v.hash(state);
175 }
176 }
177}
178
179#[derive(Debug, Clone)]
180pub struct MissingFieldInRecordError {
181 pub field_id: u64,
182}
183
184impl MechErrorKind2 for MissingFieldInRecordError {
185 fn name(&self) -> &str {
186 "MissingFieldInRecord"
187 }
188 fn message(&self) -> String {
189 format!("Record is missing required field `{}`.", self.field_id)
190 }
191}
192
193#[derive(Debug, Clone)]
194pub struct MissingKindForFieldError {
195 pub field_id: u64,
196}
197
198impl MechErrorKind2 for MissingKindForFieldError {
199 fn name(&self) -> &str {
200 "MissingKindForField"
201 }
202 fn message(&self) -> String {
203 format!("Missing expected kind for field `{}` in schema.", self.field_id)
204 }
205}
206
207#[derive(Debug, Clone)]
208pub struct MissingKindInComparedRecordError {
209 pub field_id: u64,
210}
211
212impl MechErrorKind2 for MissingKindInComparedRecordError {
213 fn name(&self) -> &str {
214 "MissingKindInComparedRecord"
215 }
216 fn message(&self) -> String {
217 format!("Missing kind for field `{}` in the compared record.", self.field_id)
218 }
219}
220
221#[derive(Debug, Clone)]
222pub struct RecordFieldKindMismatchError {
223 pub field_id: u64,
224 pub expected_kind: ValueKind,
225 pub actual_kind: ValueKind,
226}
227
228impl MechErrorKind2 for RecordFieldKindMismatchError {
229 fn name(&self) -> &str {
230 "RecordFieldKindMismatch"
231 }
232 fn message(&self) -> String {
233 format!(
234 "Kind mismatch for column `{}` (expected `{}`, found `{}`).",
235 self.field_id, self.expected_kind, self.actual_kind
236 )
237 }
238}
239
240#[derive(Debug, Clone)]
241pub struct RecordFieldNameMismatchError {
242 pub field_id: u64,
243 pub expected_name: Option<String>,
244 pub actual_name: Option<String>,
245}
246
247impl MechErrorKind2 for RecordFieldNameMismatchError {
248 fn name(&self) -> &str {
249 "RecordFieldNameMismatch"
250 }
251 fn message(&self) -> String {
252 match (&self.expected_name, &self.actual_name) {
253 (Some(e), Some(a)) => format!(
254 "Field name mismatch for field `{}` (expected `{}`, found `{}`).",
255 self.field_id, e, a
256 ),
257 (Some(e), None) => format!(
258 "Field name mismatch for field `{}` (expected `{}`, but no field found).",
259 self.field_id, e
260 ),
261 _ => format!("Field name mismatch for field `{}`.", self.field_id),
262 }
263 }
264}
265
266#[derive(Debug, Clone)]
267pub struct KeyNotFoundInKeyIndexError {
268 pub field_id: u64,
269}
270
271impl MechErrorKind2 for KeyNotFoundInKeyIndexError {
272 fn name(&self) -> &str {
273 "KeyNotFoundInKeyIndex"
274 }
275 fn message(&self) -> String {
276 format!("Key id `{}` not found in key_index.", self.field_id)
277 }
278}