wp_model_core/model/data/
record.rs1use 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};
9
10use super::field::Field;
11pub const WP_EVENT_ID: &str = "wp_event_id";
12pub trait RecordItem {
14 fn get_name(&self) -> &str;
15 fn get_meta(&self) -> &DataType;
16 fn get_value(&self) -> &Value;
17 fn get_value_mut(&mut self) -> &mut Value;
18}
19
20pub trait RecordItemFactory {
22 fn from_digit<S: Into<FNameStr>>(name: S, val: i64) -> Self;
23 fn from_ip<S: Into<FNameStr>>(name: S, ip: IpAddr) -> Self;
24 fn from_chars<N: Into<FNameStr>, Val: Into<FValueStr>>(name: N, val: Val) -> Self;
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
28pub struct Record<T> {
29 pub items: Vec<T>,
30}
31
32impl<T> Default for Record<T> {
33 fn default() -> Self {
34 Self {
35 items: Vec::with_capacity(10),
36 }
37 }
38}
39
40impl<T> From<Vec<T>> for Record<T> {
41 fn from(value: Vec<T>) -> Self {
42 Self { items: value }
43 }
44}
45
46impl<T> Display for Record<T>
47where
48 T: RecordItem + LevelFormatAble,
49{
50 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
51 writeln!(f)?;
52 for (i, o) in self.items.iter().enumerate() {
53 if *o.get_meta() != DataType::Ignore {
54 write!(f, "NO:{:<5}", i + 1)?;
55 o.level_fmt(f, 1)?;
56 }
57 }
58 Ok(())
59 }
60}
61
62impl<T> Record<T>
63where
64 T: RecordItem + RecordItemFactory,
65{
66 pub fn set_id(&mut self, id: u64) {
67 if self.items.iter().any(|f| f.get_name() == WP_EVENT_ID) {
69 return;
70 }
71 let Ok(id_i64) = i64::try_from(id) else {
72 return;
74 };
75 self.items.insert(0, T::from_digit(WP_EVENT_ID, id_i64));
76 }
77 pub fn test_value() -> Self {
78 let data = vec![
79 T::from_ip("ip", IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
80 T::from_chars("chars", "test"),
81 ];
82 Self { items: data }
83 }
84}
85
86impl<T> Record<T>
87where
88 T: RecordItem,
89{
90 pub fn get_value(&self, key: &str) -> Option<&Value> {
91 self.items
92 .iter()
93 .find(|x| x.get_name() == key)
94 .map(|x| x.get_value())
95 }
96}
97
98impl<T> Record<T> {
99 pub fn append(&mut self, data: T) {
100 self.items.push(data);
101 }
102 pub fn merge(&mut self, mut other: Self) {
103 self.items.append(&mut other.items);
104 }
105}
106
107impl<T> Record<T>
108where
109 T: RecordItem,
110{
111 pub fn field(&self, key: &str) -> Option<&T> {
113 self.items.iter().find(|item| item.get_name() == key)
114 }
115
116 pub fn get2(&self, name: &str) -> Option<&T> {
117 self.items.iter().find(|x| x.get_name() == name)
118 }
119 pub fn get_value_mut(&mut self, name: &str) -> Option<&mut T> {
120 self.items.iter_mut().find(|x| x.get_name() == name)
121 }
122 pub fn remove_field(&mut self, name: &str) -> bool {
123 let pos = self.items.iter().position(|x| x.get_name() == name);
124 if let Some(pos) = pos {
125 self.items.remove(pos);
126 true
127 } else {
128 false
129 }
130 }
131}
132
133impl<V> RecordItem for Field<V>
134where
135 V: AsValueRef<Value>,
136{
137 fn get_name(&self) -> &str {
138 Field::get_name(self)
139 }
140
141 fn get_meta(&self) -> &DataType {
142 Field::get_meta(self)
143 }
144
145 fn get_value(&self) -> &Value {
146 Field::get_value(self)
147 }
148
149 fn get_value_mut(&mut self) -> &mut Value {
150 Field::get_value_mut(self)
151 }
152}
153
154impl<V> RecordItemFactory for Field<V>
155where
156 V: Maker<i64> + Maker<FValueStr> + Maker<IpAddr>,
157{
158 fn from_digit<S: Into<FNameStr>>(name: S, val: i64) -> Self {
159 Field::from_digit(name, val)
160 }
161
162 fn from_ip<S: Into<FNameStr>>(name: S, ip: IpAddr) -> Self {
163 Field::from_ip(name, ip)
164 }
165
166 fn from_chars<N: Into<FNameStr>, Val: Into<FValueStr>>(name: N, val: Val) -> Self {
167 Field::from_chars(name, val)
168 }
169}
170
171#[cfg(test)]
174mod tests {
175 use super::*;
176 use crate::model::{DataField, DataRecord};
177 use std::net::Ipv4Addr;
178
179 fn make_test_record() -> DataRecord {
180 let fields = vec![
181 Field::from_chars("name", "Alice"),
182 Field::from_digit("age", 30),
183 Field::from_ip("ip", IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1))),
184 ];
185 Record::from(fields)
186 }
187
188 #[test]
191 fn test_record_default() {
192 let record: DataRecord = Record::default();
193 assert!(record.items.is_empty());
194 }
195
196 #[test]
197 fn test_record_from_vec() {
198 let fields: Vec<DataField> = vec![Field::from_digit("x", 1), Field::from_digit("y", 2)];
199 let record: DataRecord = Record::from(fields);
200 assert_eq!(record.items.len(), 2);
201 }
202
203 #[test]
204 fn test_record_test_value() {
205 let record: DataRecord = Record::test_value();
206 assert_eq!(record.items.len(), 2);
207 assert!(record.field("ip").is_some());
208 assert!(record.field("chars").is_some());
209 }
210
211 #[test]
214 fn test_record_field() {
215 let record = make_test_record();
216
217 let name_field = record.field("name");
218 assert!(name_field.is_some());
219 assert_eq!(name_field.unwrap().get_name(), "name");
220
221 let missing = record.field("missing");
222 assert!(missing.is_none());
223 }
224
225 #[test]
226 fn test_record_get2() {
227 let record = make_test_record();
228
229 let age_field = record.get2("age");
230 assert!(age_field.is_some());
231 assert_eq!(age_field.unwrap().get_meta(), &DataType::Digit);
232 }
233
234 #[test]
235 fn test_record_get_value() {
236 let record = make_test_record();
237
238 let age_value = record.get_value("age");
239 assert!(age_value.is_some());
240 assert_eq!(age_value.unwrap(), &Value::Digit(30));
241
242 let missing = record.get_value("missing");
243 assert!(missing.is_none());
244 }
245
246 #[test]
247 fn test_record_get_value_mut() {
248 let mut record = make_test_record();
249
250 let field = record.get_value_mut("age");
251 assert!(field.is_some());
252
253 if let Some(f) = field {
255 *f.get_value_mut() = Value::Digit(31);
256 }
257
258 assert_eq!(record.get_value("age"), Some(&Value::Digit(31)));
259 }
260
261 #[test]
264 fn test_record_append() {
265 let mut record: DataRecord = Record::default();
266 assert_eq!(record.items.len(), 0);
267
268 record.append(Field::from_digit("count", 100));
269 assert_eq!(record.items.len(), 1);
270
271 record.append(Field::from_chars("msg", "hello"));
272 assert_eq!(record.items.len(), 2);
273 }
274
275 #[test]
276 fn test_record_merge() {
277 let mut record1: DataRecord = Record::from(vec![Field::from_digit("a", 1)]);
278 let record2: DataRecord =
279 Record::from(vec![Field::from_digit("b", 2), Field::from_digit("c", 3)]);
280
281 record1.merge(record2);
282 assert_eq!(record1.items.len(), 3);
283 assert!(record1.field("a").is_some());
284 assert!(record1.field("b").is_some());
285 assert!(record1.field("c").is_some());
286 }
287
288 #[test]
289 fn test_record_remove_field() {
290 let mut record = make_test_record();
291 assert_eq!(record.items.len(), 3);
292
293 let removed = record.remove_field("age");
294 assert!(removed);
295 assert_eq!(record.items.len(), 2);
296 assert!(record.field("age").is_none());
297
298 let not_found = record.remove_field("nonexistent");
299 assert!(!not_found);
300 assert_eq!(record.items.len(), 2);
301 }
302
303 #[test]
306 fn test_record_set_id() {
307 let mut record = make_test_record();
308 let original_len = record.items.len();
309
310 record.set_id(12345);
311
312 assert_eq!(record.items.len(), original_len + 1);
313 assert_eq!(record.items[0].get_name(), WP_EVENT_ID);
315 assert_eq!(record.items[0].get_value(), &Value::Digit(12345));
316 }
317
318 #[test]
319 fn test_record_set_id_no_duplicate() {
320 let mut record = make_test_record();
321
322 record.set_id(100);
323 let len_after_first = record.items.len();
324
325 record.set_id(200);
327 assert_eq!(record.items.len(), len_after_first);
328 assert_eq!(record.get_value(WP_EVENT_ID), Some(&Value::Digit(100)));
330 }
331
332 #[test]
335 fn test_field_as_record_item() {
336 let field: DataField = Field::from_chars("key", "value");
337
338 assert_eq!(field.get_name(), "key");
340 assert_eq!(field.get_meta(), &DataType::Chars);
341 assert_eq!(field.get_value(), &Value::Chars("value".into()));
342 }
343
344 #[test]
345 fn test_field_record_item_get_value_mut() {
346 let mut field: DataField = Field::from_digit("num", 10);
347
348 *field.get_value_mut() = Value::Digit(20);
349 assert_eq!(field.get_value(), &Value::Digit(20));
350 }
351
352 #[test]
355 fn test_record_item_factory() {
356 let digit: DataField = <DataField as RecordItemFactory>::from_digit("n", 42);
357 assert_eq!(digit.get_meta(), &DataType::Digit);
358
359 let ip: DataField = <DataField as RecordItemFactory>::from_ip(
360 "addr",
361 IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
362 );
363 assert_eq!(ip.get_meta(), &DataType::IP);
364
365 let chars: DataField = <DataField as RecordItemFactory>::from_chars("s", "hello");
366 assert_eq!(chars.get_meta(), &DataType::Chars);
367 }
368
369 #[test]
372 fn test_record_display() {
373 let record = make_test_record();
374 let display = format!("{}", record);
375
376 assert!(display.contains("name"));
377 assert!(display.contains("age"));
378 assert!(display.contains("ip"));
379 }
380}