Skip to main content

kronicler/
row.rs

1use pyo3::prelude::*;
2use serde::{Deserialize, Serialize};
3use serde_big_array::BigArray;
4
5pub type RID = usize;
6pub type Epoch = u128;
7
8#[pyclass]
9#[derive(Debug, Eq, Clone, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
10pub enum FieldType {
11    #[serde(with = "BigArray")]
12    Name([u8; 64]),
13    Epoch(Epoch),
14}
15
16#[pymethods]
17impl FieldType {
18    fn __repr__(&self) -> String {
19        match self {
20            FieldType::Name(arr) => {
21                let name = arr
22                    .iter()
23                    .take_while(|&&c| c != 0)
24                    .map(|&c| c as char)
25                    .collect::<String>();
26
27                format!("FieldType::Name(\"{}\")", name)
28            }
29            FieldType::Epoch(e) => format!("FieldType::Epoch({})", e),
30        }
31    }
32
33    fn __str__(&self) -> String {
34        match self {
35            FieldType::Name(arr) => arr
36                .iter()
37                .take_while(|&&c| c != 0)
38                .map(|&c| c as char)
39                .collect::<String>(),
40
41            FieldType::Epoch(e) => e.to_string(),
42        }
43    }
44}
45
46pub fn create_function_name(s: &str) -> [u8; 64] {
47    let mut arr = [0u8; 64];
48    let bytes = s.as_bytes();
49    let len = bytes.len().min(64);
50    arr[..len].copy_from_slice(&bytes[..len]);
51    arr
52}
53
54impl FieldType {
55    // TODO: Use to_string trait
56    pub fn to_string(&self) -> String {
57        match self {
58            FieldType::Name(a) => {
59                let mut name_vec = vec![];
60
61                for i in 0..64 {
62                    let c = a[i];
63
64                    if c == 0 {
65                        break;
66                    }
67
68                    name_vec.push(c);
69                }
70
71                return std::str::from_utf8(&name_vec)
72                    .expect("Find string.")
73                    .to_string();
74            }
75            FieldType::Epoch(a) => {
76                return a.to_string();
77            }
78        }
79    }
80
81    pub fn get_size(&self) -> usize {
82        match self {
83            FieldType::Name(_) => 64,
84            FieldType::Epoch(_) => 16,
85        }
86    }
87}
88
89#[derive(Debug, Clone, PartialEq)]
90#[pyclass]
91pub struct Row {
92    #[pyo3(get)]
93    pub id: RID,
94    #[pyo3(get)]
95    pub fields: Vec<FieldType>,
96}
97
98impl Row {
99    pub fn new(id: RID, fields: Vec<FieldType>) -> Self {
100        Row { id, fields }
101    }
102
103    pub fn get_delta(&self) -> u128 {
104        let delta = self.fields[3].clone();
105
106        match delta {
107            FieldType::Epoch(a) => return a,
108            _ => unreachable!(),
109        }
110    }
111
112    // TODO: Use to_string trait
113    pub fn to_string(&self) -> String {
114        let name = self.fields[0].to_string();
115        let start = self.fields[1].clone();
116        let end = self.fields[2].clone();
117        let delta = self.fields[3].clone();
118
119        format!(
120            "Row {{ id: {}, fields: [\"{}\", {:?}, {:?}, {:?}]}}",
121            self.id, name, start, end, delta
122        )
123    }
124}
125
126#[pymethods]
127impl Row {
128    pub fn to_list<'py>(&self, py: Python<'py>) -> Bound<'py, pyo3::types::PyList> {
129        let list = pyo3::types::PyList::empty(py);
130        list.append(self.id).unwrap();
131
132        let mut epoch_count = 0;
133        for field in &self.fields {
134            match field {
135                FieldType::Name(arr) => {
136                    let name: String = arr
137                        .iter()
138                        .take_while(|&&c| c != 0)
139                        .map(|&c| c as char)
140                        .collect();
141                    list.append(name).unwrap();
142                }
143                FieldType::Epoch(e) => {
144                    epoch_count += 1;
145                    if epoch_count != 2 {
146                        // Skip the 2nd epoch (end time)
147                        list.append(*e).unwrap();
148                    }
149                }
150            }
151        }
152
153        list
154    }
155
156    fn __str__(&self) -> String {
157        let name = self.fields[0].to_string();
158        let start = self.fields[1].clone();
159        let end = self.fields[2].clone();
160        let delta = self.fields[3].clone();
161
162        format!(
163            "Row(id={}, fields=[\"{}\", {:?}, {:?}, {:?}])",
164            self.id, name, start, end, delta
165        )
166    }
167
168    fn __repr__(&self) -> String {
169        self.__str__()
170    }
171}
172
173#[cfg(test)]
174mod tests {
175    use super::*;
176
177    #[test]
178    fn fieldtype_name_to_string() {
179        let name = FieldType::Name(create_function_name("test_function"));
180        assert_eq!(name.to_string(), "test_function");
181    }
182
183    #[test]
184    fn fieldtype_name_to_string_with_nulls() {
185        let mut arr = [0u8; 64];
186        arr[0] = b't';
187        arr[1] = b'e';
188        arr[2] = b's';
189        arr[3] = b't';
190        // Rest are zeros
191        let name = FieldType::Name(arr);
192        assert_eq!(name.to_string(), "test");
193    }
194
195    #[test]
196    fn fieldtype_name_get_size() {
197        let name = FieldType::Name(create_function_name("any_name"));
198        assert_eq!(name.get_size(), 64);
199    }
200
201    #[test]
202    fn fieldtype_name_str() {
203        let name = FieldType::Name(create_function_name("my_function"));
204        assert_eq!(name.__str__(), "my_function");
205    }
206
207    #[test]
208    fn fieldtype_name_repr() {
209        let name = FieldType::Name(create_function_name("my_function"));
210        assert_eq!(name.__repr__(), "FieldType::Name(\"my_function\")");
211    }
212
213    // FieldType::Epoch tests
214    #[test]
215    fn fieldtype_epoch_to_string() {
216        let epoch = FieldType::Epoch(1234567890);
217        assert_eq!(epoch.to_string(), "1234567890");
218    }
219
220    #[test]
221    fn fieldtype_epoch_get_size() {
222        let epoch = FieldType::Epoch(999);
223        assert_eq!(epoch.get_size(), 16);
224    }
225
226    #[test]
227    fn fieldtype_epoch_str() {
228        let epoch = FieldType::Epoch(42);
229        assert_eq!(epoch.__str__(), "42");
230    }
231
232    #[test]
233    fn fieldtype_epoch_repr() {
234        let epoch = FieldType::Epoch(42);
235        assert_eq!(epoch.__repr__(), "FieldType::Epoch(42)");
236    }
237
238    #[test]
239    fn fieldtype_equality() {
240        let epoch1 = FieldType::Epoch(100);
241        let epoch2 = FieldType::Epoch(100);
242        let epoch3 = FieldType::Epoch(200);
243
244        assert_eq!(epoch1, epoch2);
245        assert_ne!(epoch1, epoch3);
246    }
247
248    #[test]
249    fn fieldtype_ordering() {
250        let epoch1 = FieldType::Epoch(100);
251        let epoch2 = FieldType::Epoch(200);
252
253        assert!(epoch1 < epoch2);
254        assert!(epoch2 > epoch1);
255    }
256
257    #[test]
258    fn fieldtype_clone() {
259        let original = FieldType::Epoch(500);
260        let cloned = original.clone();
261        assert_eq!(original, cloned);
262    }
263
264    #[test]
265    fn row_new() {
266        let fields = vec![
267            FieldType::Name(create_function_name("test")),
268            FieldType::Epoch(1),
269            FieldType::Epoch(2),
270            FieldType::Epoch(1),
271        ];
272        let row = Row::new(100, fields.clone());
273
274        assert_eq!(row.id, 100);
275        assert_eq!(row.fields, fields);
276    }
277
278    #[test]
279    fn row_get_delta() {
280        let row = Row {
281            id: 1,
282            fields: vec![
283                FieldType::Name(create_function_name("func")),
284                FieldType::Epoch(1000),
285                FieldType::Epoch(2000),
286                FieldType::Epoch(1000), // delta
287            ],
288        };
289
290        assert_eq!(row.get_delta(), 1000);
291    }
292
293    #[test]
294    fn row_to_string_test() {
295        let r = Row {
296            id: 1000,
297            fields: vec![
298                FieldType::Epoch(1),
299                FieldType::Epoch(1),
300                FieldType::Epoch(1),
301                FieldType::Epoch(1),
302            ],
303        };
304
305        assert_eq!(
306            r.to_string(),
307            "Row { id: 1000, fields: [\"1\", Epoch(1), Epoch(1), Epoch(1)]}"
308        );
309    }
310
311    #[test]
312    fn row_to_string_with_name() {
313        let r = Row {
314            id: 500,
315            fields: vec![
316                FieldType::Name(create_function_name("my_function")),
317                FieldType::Epoch(1000),
318                FieldType::Epoch(2000),
319                FieldType::Epoch(1000),
320            ],
321        };
322
323        assert_eq!(
324            r.to_string(),
325            "Row { id: 500, fields: [\"my_function\", Epoch(1000), Epoch(2000), Epoch(1000)]}"
326        );
327    }
328
329    #[test]
330    fn row_str() {
331        let r = Row {
332            id: 42,
333            fields: vec![
334                FieldType::Name(create_function_name("test")),
335                FieldType::Epoch(100),
336                FieldType::Epoch(200),
337                FieldType::Epoch(100),
338            ],
339        };
340
341        assert_eq!(
342            r.__str__(),
343            "Row(id=42, fields=[\"test\", Epoch(100), Epoch(200), Epoch(100)])"
344        );
345    }
346
347    #[test]
348    fn row_repr() {
349        let r = Row {
350            id: 42,
351            fields: vec![
352                FieldType::Name(create_function_name("test")),
353                FieldType::Epoch(100),
354                FieldType::Epoch(200),
355                FieldType::Epoch(100),
356            ],
357        };
358
359        assert_eq!(r.__repr__(), r.__str__());
360    }
361
362    #[test]
363    fn row_clone() {
364        let original = Row {
365            id: 10,
366            fields: vec![FieldType::Epoch(1), FieldType::Epoch(2)],
367        };
368        let cloned = original.clone();
369
370        assert_eq!(original, cloned);
371    }
372
373    #[test]
374    fn row_equality() {
375        let row1 = Row {
376            id: 1,
377            fields: vec![FieldType::Epoch(100)],
378        };
379        let row2 = Row {
380            id: 1,
381            fields: vec![FieldType::Epoch(100)],
382        };
383        let row3 = Row {
384            id: 2,
385            fields: vec![FieldType::Epoch(100)],
386        };
387
388        assert_eq!(row1, row2);
389        assert_ne!(row1, row3);
390    }
391
392    #[test]
393    fn fieldtype_empty_name() {
394        let name = FieldType::Name([0u8; 64]);
395        assert_eq!(name.to_string(), "");
396    }
397
398    #[test]
399    fn fieldtype_max_length_name() {
400        let arr = [b'a'; 64];
401        let name = FieldType::Name(arr);
402        let result = name.to_string();
403        assert_eq!(result.len(), 64);
404        assert_eq!(result, "a".repeat(64));
405    }
406
407    #[test]
408    fn fieldtype_epoch_zero() {
409        let epoch = FieldType::Epoch(0);
410        assert_eq!(epoch.to_string(), "0");
411    }
412
413    #[test]
414    fn fieldtype_epoch_large_value() {
415        let epoch = FieldType::Epoch(u128::MAX);
416        assert_eq!(epoch.to_string(), u128::MAX.to_string());
417    }
418
419    #[test]
420    fn row_empty_fields() {
421        let row = Row::new(1, vec![]);
422        assert_eq!(row.id, 1);
423        assert_eq!(row.fields.len(), 0);
424    }
425
426    #[test]
427    fn row_single_field() {
428        let row = Row::new(10, vec![FieldType::Epoch(999)]);
429        assert_eq!(row.fields.len(), 1);
430    }
431
432    #[test]
433    fn row_many_fields() {
434        let fields = vec![
435            FieldType::Epoch(1),
436            FieldType::Epoch(2),
437            FieldType::Epoch(3),
438            FieldType::Epoch(4),
439            FieldType::Epoch(5),
440        ];
441        let row = Row::new(1, fields.clone());
442        assert_eq!(row.fields.len(), 5);
443    }
444}