wp_model_core/model/data/
field.rs1use crate::model::DataType;
2use crate::model::format::LevelFormatAble;
3use crate::model::{FNameStr, FValueStr};
4
5use crate::model::Value;
6use crate::traits::AsValueRef;
7use serde::Deserialize;
8use serde::Serialize;
9use std::fmt::{Display, Formatter};
10use std::rc::Rc;
11use std::sync::Arc;
12
13#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
14pub struct Field<T> {
15 pub meta: DataType,
16 pub name: FNameStr,
17 pub value: T,
18}
19
20pub trait ValueRef<T> {
22 fn value_ref(&self) -> &T;
24}
25
26impl<T> ValueRef<T> for Field<T> {
27 fn value_ref(&self) -> &T {
28 &self.value
29 }
30}
31
32impl<T> From<Field<T>> for Field<Rc<T>> {
33 fn from(other: Field<T>) -> Self {
34 let value = Rc::<T>::from(other.value);
35 Self {
36 meta: other.meta,
37 name: other.name,
38 value,
39 }
40 }
41}
42
43impl<T> From<Field<T>> for Field<Arc<T>> {
44 fn from(other: Field<T>) -> Self {
45 let value = Arc::<T>::from(other.value);
46 Self {
47 meta: other.meta,
48 name: other.name,
49 value,
50 }
51 }
52}
53
54impl<T> Field<T> {
55 pub fn new<S: Into<FNameStr>, V: Into<T>>(meta: DataType, name: S, value: V) -> Self {
56 Self {
57 meta,
58 name: name.into(),
59 value: value.into(),
60 }
61 }
62
63 pub fn new_opt(meta: DataType, name: Option<FNameStr>, value: T) -> Self {
64 let name = name.unwrap_or_else(|| FNameStr::from(String::from(&meta)));
65 Field { meta, name, value }
66 }
67
68 pub fn get_name(&self) -> &str {
69 self.name.as_str()
70 }
71 pub fn clone_name(&self) -> String {
72 self.name.as_str().to_string()
73 }
74 pub fn get_meta(&self) -> &DataType {
75 &self.meta
76 }
77
78 pub fn set_name<S: Into<FNameStr>>(&mut self, name: S) {
79 self.name = name.into()
80 }
81}
82
83impl Field<Value> {
84 pub fn from_shared_chars<S: Into<FNameStr>>(name: S, val: FValueStr) -> Self {
85 Self::new(DataType::Chars, name.into(), Value::Chars(val))
86 }
87
88 pub fn get_chars(&self) -> Option<&str> {
89 self.value.as_str()
90 }
91
92 pub fn get_chars_mut(&mut self) -> Option<&mut FValueStr> {
93 self.value.ensure_owned_chars()
94 }
95}
96impl<T> Field<T>
97where
98 T: AsValueRef<Value>,
99{
100 pub fn get_value(&self) -> &Value {
101 self.value.as_value_ref()
102 }
104
105 pub fn get_value_mut(&mut self) -> &mut Value {
106 self.value.as_value_mutref()
107 }
108}
109
110impl<T> LevelFormatAble for Field<T>
111where
112 T: Display,
113{
114 fn level_fmt(&self, f: &mut Formatter<'_>, level: usize) -> std::fmt::Result {
115 let meta: String = From::from(&self.meta);
116 writeln!(
117 f,
118 "{:width$}[{:<16}] {:<20} : {}",
119 "",
120 meta,
121 self.name,
122 self.value,
123 width = level * 6
124 )?;
125 Ok(())
126 }
127}
128
129impl<T> Display for Field<T>
130where
131 T: Display,
132{
133 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
134 write!(f, "{}({})", self.meta, self.value)
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141 use crate::model::{DataField, FValueStr};
142
143 #[test]
146 fn test_field_new() {
147 let field: Field<i64> = Field::new(DataType::Digit, "count", 42i64);
148 assert_eq!(field.meta, DataType::Digit);
149 assert_eq!(field.get_name(), "count");
150 assert_eq!(field.value, 42);
151 }
152
153 #[test]
154 fn test_field_new_with_string_conversion() {
155 let field: Field<String> = Field::new(DataType::Chars, String::from("key"), "value");
156 assert_eq!(field.get_name(), "key");
157 assert_eq!(field.value, "value");
158 }
159
160 #[test]
161 fn test_field_new_opt_with_name() {
162 let field: Field<i64> = Field::new_opt(DataType::Digit, Some("num".into()), 100);
163 assert_eq!(field.get_name(), "num");
164 assert_eq!(field.value, 100);
165 }
166
167 #[test]
168 fn test_field_new_opt_without_name() {
169 let field: Field<i64> = Field::new_opt(DataType::Digit, None, 50);
170 assert_eq!(field.get_name(), "digit");
172 assert_eq!(field.value, 50);
173 }
174
175 #[test]
178 fn test_field_get_name() {
179 let field: Field<i64> = Field::new(DataType::Digit, "test_name", 1);
180 assert_eq!(field.get_name(), "test_name");
181 }
182
183 #[test]
184 fn test_field_clone_name() {
185 let field: Field<i64> = Field::new(DataType::Digit, "original", 1);
186 let cloned = field.clone_name();
187 assert_eq!(cloned, "original");
188 assert_eq!(cloned, field.get_name());
190 }
191
192 #[test]
193 fn test_field_get_meta() {
194 let field: Field<i64> = Field::new(DataType::Float, "val", 1);
195 assert_eq!(field.get_meta(), &DataType::Float);
196 }
197
198 #[test]
199 fn test_field_set_name() {
200 let mut field: Field<i64> = Field::new(DataType::Digit, "old_name", 1);
201 field.set_name("new_name");
202 assert_eq!(field.get_name(), "new_name");
203 }
204
205 #[test]
208 fn test_value_ref_trait() {
209 let field: Field<i64> = Field::new(DataType::Digit, "num", 42);
210 assert_eq!(field.value_ref(), &42);
211 }
212
213 #[test]
216 fn test_field_get_value() {
217 let field: DataField = Field::new(DataType::Digit, "num", Value::Digit(99));
218 assert_eq!(field.get_value(), &Value::Digit(99));
219 }
220
221 #[test]
222 fn test_field_get_value_mut() {
223 let mut field: DataField = Field::new(DataType::Digit, "num", Value::Digit(10));
224 *field.get_value_mut() = Value::Digit(20);
225 assert_eq!(field.get_value(), &Value::Digit(20));
226 }
227
228 #[test]
229 fn test_field_from_shared_chars() {
230 let s = FValueStr::from("hello");
231 let field: DataField = Field::from_shared_chars("msg", s.clone());
232 assert_eq!(field.get_name(), "msg");
233 assert_eq!(field.get_meta(), &DataType::Chars);
234 assert!(matches!(field.value, Value::Chars(_)));
235 assert_eq!(field.get_chars(), Some("hello"));
236 }
237
238 #[test]
239 fn test_field_get_chars_mut() {
240 let s = FValueStr::from("foo");
241 let mut field: DataField = Field::from_shared_chars("msg", s);
242 {
243 let value = field.get_chars_mut().expect("mutable");
244 *value = FValueStr::from(format!("{}-bar", value.as_str()));
246 }
247 assert!(matches!(field.value, Value::Chars(_)));
248 assert_eq!(field.get_chars(), Some("foo-bar"));
249 }
250
251 #[test]
254 fn test_field_to_rc() {
255 let field: Field<i64> = Field::new(DataType::Digit, "num", 42);
256 let rc_field: Field<Rc<i64>> = field.into();
257
258 assert_eq!(rc_field.get_name(), "num");
259 assert_eq!(rc_field.meta, DataType::Digit);
260 assert_eq!(*rc_field.value, 42);
261 }
262
263 #[test]
264 fn test_field_to_arc() {
265 let field: Field<String> = Field::new(DataType::Chars, "msg", String::from("hello"));
266 let arc_field: Field<Arc<String>> = field.into();
267
268 assert_eq!(arc_field.get_name(), "msg");
269 assert_eq!(arc_field.meta, DataType::Chars);
270 assert_eq!(*arc_field.value, "hello");
271 }
272
273 #[test]
276 fn test_field_display() {
277 let field: Field<i64> = Field::new(DataType::Digit, "count", 42);
278 let display = format!("{}", field);
279 assert!(display.contains("digit"));
280 assert!(display.contains("42"));
281 }
282
283 #[test]
284 fn test_field_display_chars() {
285 let field: Field<String> = Field::new(DataType::Chars, "msg", String::from("hello"));
286 let display = format!("{}", field);
287 assert!(display.contains("chars"));
288 assert!(display.contains("hello"));
289 }
290
291 #[test]
294 fn test_level_format_able() {
295 let field: Field<i64> = Field::new(DataType::Digit, "level_test", 123);
296 let mut output = String::new();
297 use std::fmt::Write;
298 let _ = write!(output, "{}", field);
300 assert!(output.contains("digit"));
301 assert!(output.contains("123"));
302 }
303
304 #[test]
307 fn test_field_clone() {
308 let field: Field<i64> = Field::new(DataType::Digit, "num", 42);
309 let cloned = field.clone();
310
311 assert_eq!(field, cloned);
312 assert_eq!(cloned.get_name(), "num");
313 assert_eq!(cloned.value, 42);
314 }
315
316 #[test]
317 fn test_field_partial_eq() {
318 let field1: Field<i64> = Field::new(DataType::Digit, "num", 42);
319 let field2: Field<i64> = Field::new(DataType::Digit, "num", 42);
320 let field3: Field<i64> = Field::new(DataType::Digit, "num", 99);
321
322 assert_eq!(field1, field2);
323 assert_ne!(field1, field3);
324 }
325
326 #[test]
329 fn test_field_serde_roundtrip() {
330 let field: Field<i64> = Field::new(DataType::Digit, "serde_test", 123);
331 let json = serde_json::to_string(&field).unwrap();
332 let parsed: Field<i64> = serde_json::from_str(&json).unwrap();
333
334 assert_eq!(field, parsed);
335 }
336
337 #[test]
338 fn test_field_serde_with_string() {
339 let field: Field<String> = Field::new(DataType::Chars, "msg", String::from("test"));
340 let json = serde_json::to_string(&field).unwrap();
341 let parsed: Field<String> = serde_json::from_str(&json).unwrap();
342
343 assert_eq!(field.name, parsed.name);
344 assert_eq!(field.value, parsed.value);
345 }
346}