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