1use crate::model::Maker;
2use crate::model::format::LevelFormatAble;
3use crate::model::{DataType, FNameStr, FValueStr, Value};
4use crate::traits::AsValueRef;
5use serde_derive::{Deserialize, Serialize};
6use std::convert::TryFrom;
7use std::fmt::{Display, Formatter};
8use std::net::{IpAddr, Ipv4Addr};
9use std::sync::Arc;
10
11use super::field::Field;
12use super::storage::FieldStorage;
13pub const WP_EVENT_ID: &str = "wp_event_id";
14pub trait RecordItem {
16 fn get_name(&self) -> &str;
17 fn get_meta(&self) -> &DataType;
18 fn get_value(&self) -> &Value;
19 fn get_value_mut(&mut self) -> &mut Value;
20}
21
22pub trait RecordItemFactory {
24 fn from_digit<S: Into<FNameStr>>(name: S, val: i64) -> Self;
25 fn from_ip<S: Into<FNameStr>>(name: S, ip: IpAddr) -> Self;
26 fn from_chars<N: Into<FNameStr>, Val: Into<FValueStr>>(name: N, val: Val) -> Self;
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
30pub struct Record<T> {
31 pub id: u64,
32 pub items: Vec<T>,
33}
34
35impl<T> Default for Record<T> {
36 fn default() -> Self {
37 Self {
38 id: 0,
39 items: Vec::with_capacity(10),
40 }
41 }
42}
43
44impl<T> From<Vec<T>> for Record<T> {
45 fn from(value: Vec<T>) -> Self {
46 Self {
47 id: 0,
48 items: value,
49 }
50 }
51}
52
53impl<T> Display for Record<T>
54where
55 T: RecordItem + LevelFormatAble,
56{
57 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
58 writeln!(f)?;
59 for (i, o) in self.items.iter().enumerate() {
60 if *o.get_meta() != DataType::Ignore {
61 write!(f, "NO:{:<5}", i + 1)?;
62 o.level_fmt(f, 1)?;
63 }
64 }
65 Ok(())
66 }
67}
68
69impl<T> Record<T>
70where
71 T: RecordItem + RecordItemFactory,
72{
73 pub fn set_id(&mut self, id: u64) {
74 self.id = id;
76
77 if self.items.iter().any(|f| f.get_name() == WP_EVENT_ID) {
79 return;
80 }
81 let Ok(id_i64) = i64::try_from(id) else {
82 return;
84 };
85 self.items.insert(0, T::from_digit(WP_EVENT_ID, id_i64));
86 }
87 pub fn test_value() -> Self {
88 let data = vec![
89 T::from_ip("ip", IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
90 T::from_chars("chars", "test"),
91 ];
92 Self { id: 0, items: data }
93 }
94}
95
96impl<T> Record<T>
97where
98 T: RecordItem,
99{
100 pub fn get_value(&self, key: &str) -> Option<&Value> {
101 self.items
102 .iter()
103 .find(|x| x.get_name() == key)
104 .map(|x| x.get_value())
105 }
106}
107
108impl<T> Record<T> {
109 pub fn append(&mut self, data: T) {
110 self.items.push(data);
111 }
112 pub fn merge(&mut self, mut other: Self) {
113 self.items.append(&mut other.items);
114 }
115}
116
117impl<T> Record<T>
118where
119 T: RecordItem,
120{
121 pub fn field(&self, key: &str) -> Option<&T> {
123 self.items.iter().find(|item| item.get_name() == key)
124 }
125
126 pub fn get2(&self, name: &str) -> Option<&T> {
127 self.items.iter().find(|x| x.get_name() == name)
128 }
129 pub fn get_value_mut(&mut self, name: &str) -> Option<&mut T> {
130 self.items.iter_mut().find(|x| x.get_name() == name)
131 }
132 pub fn remove_field(&mut self, name: &str) -> bool {
133 let pos = self.items.iter().position(|x| x.get_name() == name);
134 if let Some(pos) = pos {
135 self.items.remove(pos);
136 true
137 } else {
138 false
139 }
140 }
141}
142
143impl<V> RecordItem for Field<V>
144where
145 V: AsValueRef<Value>,
146{
147 fn get_name(&self) -> &str {
148 Field::get_name(self)
149 }
150
151 fn get_meta(&self) -> &DataType {
152 Field::get_meta(self)
153 }
154
155 fn get_value(&self) -> &Value {
156 Field::get_value(self)
157 }
158
159 fn get_value_mut(&mut self) -> &mut Value {
160 Field::get_value_mut(self)
161 }
162}
163
164impl<V> RecordItemFactory for Field<V>
165where
166 V: Maker<i64> + Maker<FValueStr> + Maker<IpAddr>,
167{
168 fn from_digit<S: Into<FNameStr>>(name: S, val: i64) -> Self {
169 Field::from_digit(name, val)
170 }
171
172 fn from_ip<S: Into<FNameStr>>(name: S, ip: IpAddr) -> Self {
173 Field::from_ip(name, ip)
174 }
175
176 fn from_chars<N: Into<FNameStr>, Val: Into<FValueStr>>(name: N, val: Val) -> Self {
177 Field::from_chars(name, val)
178 }
179}
180
181impl Record<FieldStorage> {
183 pub fn push_shared(&mut self, field: Arc<Field<Value>>) {
196 self.items.push(FieldStorage::Shared(field));
197 }
198
199 pub fn push_owned(&mut self, field: Field<Value>) {
211 self.items.push(FieldStorage::Owned(field));
212 }
213
214 pub fn get_field(&self, index: usize) -> Option<&Field<Value>> {
230 self.items.get(index).map(|s| s.as_field())
231 }
232
233 pub fn storage_stats(&self) -> (usize, usize) {
255 let mut shared_count = 0;
256 let mut owned_count = 0;
257 for item in &self.items {
258 match item {
259 FieldStorage::Shared(_) => shared_count += 1,
260 FieldStorage::Owned(_) => owned_count += 1,
261 }
262 }
263 (shared_count, owned_count)
264 }
265
266 pub fn into_owned_record(self) -> Record<Field<Value>> {
284 Record {
285 id: self.id,
286 items: self
287 .items
288 .into_iter()
289 .map(|storage| storage.into_owned())
290 .collect(),
291 }
292 }
293}
294
295#[cfg(test)]
298mod tests {
299 use super::*;
300 use crate::model::{DataField, DataRecord, FieldStorage};
301 use std::net::Ipv4Addr;
302
303 fn make_test_record() -> DataRecord {
304 let fields = vec![
305 FieldStorage::from_chars("name", "Alice"),
306 FieldStorage::from_digit("age", 30),
307 FieldStorage::from_ip("ip", IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1))),
308 ];
309 Record::from(fields)
310 }
311
312 #[test]
315 fn test_record_default() {
316 let record: DataRecord = Record::default();
317 assert!(record.items.is_empty());
318 }
319
320 #[test]
321 fn test_record_from_vec() {
322 let fields: Vec<FieldStorage> = vec![
323 FieldStorage::from_digit("x", 1),
324 FieldStorage::from_digit("y", 2),
325 ];
326 let record: DataRecord = Record::from(fields);
327 assert_eq!(record.items.len(), 2);
328 }
329
330 #[test]
331 fn test_record_test_value() {
332 let record: DataRecord = Record::test_value();
333 assert_eq!(record.items.len(), 2);
334 assert!(record.field("ip").is_some());
335 assert!(record.field("chars").is_some());
336 }
337
338 #[test]
341 fn test_record_field() {
342 let record = make_test_record();
343
344 let name_field = record.field("name");
345 assert!(name_field.is_some());
346 assert_eq!(name_field.unwrap().get_name(), "name");
347
348 let missing = record.field("missing");
349 assert!(missing.is_none());
350 }
351
352 #[test]
353 fn test_record_get2() {
354 let record = make_test_record();
355
356 let age_field = record.get2("age");
357 assert!(age_field.is_some());
358 assert_eq!(age_field.unwrap().get_meta(), &DataType::Digit);
359 }
360
361 #[test]
362 fn test_record_get_value() {
363 let record = make_test_record();
364
365 let age_value = record.get_value("age");
366 assert!(age_value.is_some());
367 assert_eq!(age_value.unwrap(), &Value::Digit(30));
368
369 let missing = record.get_value("missing");
370 assert!(missing.is_none());
371 }
372
373 #[test]
374 fn test_record_get_value_mut() {
375 let mut record = make_test_record();
376
377 let field = record.get_value_mut("age");
378 assert!(field.is_some());
379
380 if let Some(f) = field {
382 *f.get_value_mut() = Value::Digit(31);
383 }
384
385 assert_eq!(record.get_value("age"), Some(&Value::Digit(31)));
386 }
387
388 #[test]
391 fn test_record_append() {
392 let mut record: DataRecord = Record::default();
393 assert_eq!(record.items.len(), 0);
394
395 record.append(FieldStorage::from_digit("count", 100));
396 assert_eq!(record.items.len(), 1);
397
398 record.append(FieldStorage::from_chars("msg", "hello"));
399 assert_eq!(record.items.len(), 2);
400 }
401
402 #[test]
403 fn test_record_merge() {
404 let mut record1: DataRecord = Record::from(vec![FieldStorage::from_digit("a", 1)]);
405 let record2: DataRecord = Record::from(vec![
406 FieldStorage::from_digit("b", 2),
407 FieldStorage::from_digit("c", 3),
408 ]);
409
410 record1.merge(record2);
411 assert_eq!(record1.items.len(), 3);
412 assert!(record1.field("a").is_some());
413 assert!(record1.field("b").is_some());
414 assert!(record1.field("c").is_some());
415 }
416
417 #[test]
418 fn test_record_remove_field() {
419 let mut record = make_test_record();
420 assert_eq!(record.items.len(), 3);
421
422 let removed = record.remove_field("age");
423 assert!(removed);
424 assert_eq!(record.items.len(), 2);
425 assert!(record.field("age").is_none());
426
427 let not_found = record.remove_field("nonexistent");
428 assert!(!not_found);
429 assert_eq!(record.items.len(), 2);
430 }
431
432 #[test]
435 fn test_record_set_id() {
436 let mut record = make_test_record();
437 let original_len = record.items.len();
438
439 record.set_id(12345);
440
441 assert_eq!(record.id, 12345);
443 assert_eq!(record.items.len(), original_len + 1);
444 assert_eq!(record.items[0].get_name(), WP_EVENT_ID);
446 assert_eq!(record.items[0].get_value(), &Value::Digit(12345));
447 }
448
449 #[test]
450 fn test_record_set_id_no_duplicate() {
451 let mut record = make_test_record();
452
453 record.set_id(100);
454 assert_eq!(record.id, 100);
455 let len_after_first = record.items.len();
456
457 record.set_id(200);
459 assert_eq!(record.id, 200);
460 assert_eq!(record.items.len(), len_after_first);
461 assert_eq!(record.get_value(WP_EVENT_ID), Some(&Value::Digit(100)));
463 }
464
465 #[test]
468 fn test_field_as_record_item() {
469 let field: DataField = Field::from_chars("key", "value");
470
471 assert_eq!(field.get_name(), "key");
473 assert_eq!(field.get_meta(), &DataType::Chars);
474 assert_eq!(field.get_value(), &Value::Chars("value".into()));
475 }
476
477 #[test]
478 fn test_field_record_item_get_value_mut() {
479 let mut field: DataField = Field::from_digit("num", 10);
480
481 *field.get_value_mut() = Value::Digit(20);
482 assert_eq!(field.get_value(), &Value::Digit(20));
483 }
484
485 #[test]
488 fn test_field_storage_as_record_item() {
489 let storage: FieldStorage = FieldStorage::from_chars("key", "value");
490
491 assert_eq!(storage.get_name(), "key");
493 assert_eq!(storage.get_meta(), &DataType::Chars);
494 assert_eq!(storage.get_value(), &Value::Chars("value".into()));
495 }
496
497 #[test]
498 fn test_field_storage_record_item_get_value_mut() {
499 let mut storage: FieldStorage = FieldStorage::from_digit("num", 10);
500
501 *storage.get_value_mut() = Value::Digit(20);
502 assert_eq!(storage.get_value(), &Value::Digit(20));
503 }
504
505 #[test]
508 fn test_record_item_factory() {
509 let digit: FieldStorage = <FieldStorage as RecordItemFactory>::from_digit("n", 42);
510 assert_eq!(digit.get_meta(), &DataType::Digit);
511
512 let ip: FieldStorage = <FieldStorage as RecordItemFactory>::from_ip(
513 "addr",
514 IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
515 );
516 assert_eq!(ip.get_meta(), &DataType::IP);
517
518 let chars: FieldStorage = <FieldStorage as RecordItemFactory>::from_chars("s", "hello");
519 assert_eq!(chars.get_meta(), &DataType::Chars);
520 }
521
522 #[test]
525 fn test_record_display() {
526 let record = make_test_record();
527 let display = format!("{}", record);
528
529 assert!(display.contains("name"));
530 assert!(display.contains("age"));
531 assert!(display.contains("ip"));
532 }
533
534 #[test]
537 fn test_push_shared() {
538 let mut record = DataRecord::default();
539 let field = Arc::new(Field::new(DataType::Chars, "static", Value::from("value")));
540
541 record.push_shared(field.clone());
542 assert_eq!(record.items.len(), 1);
543 assert!(record.items[0].is_shared());
544 assert_eq!(record.items[0].as_field().get_name(), "static");
545 }
546
547 #[test]
548 fn test_push_owned() {
549 let mut record = DataRecord::default();
550 let field = Field::new(DataType::Digit, "dynamic", Value::from(42));
551
552 record.push_owned(field);
553 assert_eq!(record.items.len(), 1);
554 assert!(!record.items[0].is_shared());
555 assert_eq!(record.items[0].as_field().get_name(), "dynamic");
556 }
557
558 #[test]
559 fn test_get_field() {
560 let mut record = DataRecord::default();
561 record.push_owned(Field::new(DataType::Chars, "test", Value::from("value")));
562
563 let field = record.get_field(0);
564 assert!(field.is_some());
565 assert_eq!(field.unwrap().get_name(), "test");
566
567 let missing = record.get_field(10);
568 assert!(missing.is_none());
569 }
570
571 #[test]
572 fn test_storage_stats() {
573 let mut record = DataRecord::default();
574
575 record.push_shared(Arc::new(Field::new(
577 DataType::Chars,
578 "s1",
579 Value::from("a"),
580 )));
581 record.push_shared(Arc::new(Field::new(
582 DataType::Chars,
583 "s2",
584 Value::from("b"),
585 )));
586
587 record.push_owned(Field::new(DataType::Digit, "o1", Value::from(1)));
589 record.push_owned(Field::new(DataType::Digit, "o2", Value::from(2)));
590 record.push_owned(Field::new(DataType::Digit, "o3", Value::from(3)));
591
592 let (shared, owned) = record.storage_stats();
593 assert_eq!(shared, 2);
594 assert_eq!(owned, 3);
595 }
596
597 #[test]
598 fn test_into_owned_record() {
599 let mut record = DataRecord::default();
600 record.push_shared(Arc::new(Field::new(
601 DataType::Chars,
602 "s",
603 Value::from("shared"),
604 )));
605 record.push_owned(Field::new(DataType::Digit, "o", Value::from(10)));
606
607 let owned_record = record.into_owned_record();
608 assert_eq!(owned_record.items.len(), 2);
609 assert_eq!(owned_record.items[0].get_name(), "s");
610 assert_eq!(owned_record.items[1].get_name(), "o");
611 }
612}