Skip to main content

wp_model_core/model/data/
storage.rs

1use crate::model::DataType;
2use crate::model::Value;
3use crate::model::format::LevelFormatAble;
4use crate::model::{FNameStr, FValueStr};
5use serde::{Deserialize, Deserializer, Serialize, Serializer};
6use std::fmt::{Display, Formatter};
7use std::net::IpAddr;
8use std::sync::Arc;
9
10use super::field::Field;
11use super::record::{RecordItem, RecordItemFactory};
12
13/// Mixed storage for fields supporting both Arc (zero-copy) and owned (dynamic) variants.
14///
15/// This enum allows efficient handling of both static/constant fields (via `Shared`)
16/// and dynamically computed fields (via `Owned`).
17///
18/// # Performance
19/// - Cloning `Shared` variant: ~5ns (Arc reference count increment)
20/// - Cloning `Owned` variant: 50-500ns (deep copy of Field<Value>)
21/// - Accessing field via `as_field()`: ~0-1ns
22///
23/// # Examples
24///
25/// ```ignore
26/// use std::sync::Arc;
27/// use wp_model_core::model::{FieldStorage, Field, Value, DataType};
28///
29/// // Create a shared field (for static/constant values)
30/// let static_field = Field::new(DataType::Chars, "app_name", Value::from("myapp"));
31/// let shared = FieldStorage::from_shared(static_field);
32///
33/// // Clone is cheap (only increments Arc reference count)
34/// let shared2 = shared.clone();
35///
36/// // Create an owned field (for dynamic values)
37/// let dynamic_field = Field::new(DataType::Digit, "counter", Value::from(42));
38/// let owned = FieldStorage::from_owned(dynamic_field);
39/// ```
40#[derive(Clone, Debug)]
41pub enum FieldStorage {
42    /// Shared field with reference counting for zero-copy sharing.
43    ///
44    /// Used for static/constant fields that are referenced multiple times.
45    /// Cloning this variant only increments the reference count (~5ns).
46    Shared(Arc<Field<Value>>),
47
48    /// Owned field from dynamic computation.
49    ///
50    /// Used for fields that are computed dynamically per record.
51    /// Cloning this variant performs a deep copy of the field.
52    Owned(Field<Value>),
53}
54
55impl FieldStorage {
56    /// Get a reference to the underlying field (unified interface).
57    ///
58    /// # Performance
59    /// - Shared variant: ~1ns (dereference)
60    /// - Owned variant: 0ns (direct reference)
61    ///
62    /// # Examples
63    ///
64    /// ```ignore
65    /// use wp_model_core::model::{FieldStorage, Field, Value, DataType};
66    ///
67    /// let field = Field::new(DataType::Chars, "test", Value::from("value"));
68    /// let storage = FieldStorage::from_owned(field);
69    ///
70    /// assert_eq!(storage.as_field().get_name(), "test");
71    /// ```
72    #[inline]
73    pub fn as_field(&self) -> &Field<Value> {
74        match self {
75            FieldStorage::Shared(arc) => arc.as_ref(),
76            FieldStorage::Owned(field) => field,
77        }
78    }
79
80    /// Convert to owned Field<Value>.
81    ///
82    /// # Performance
83    /// - Shared variant: ~50-500ns (clone the inner field if multiple references exist)
84    /// - Owned variant: 0ns (move)
85    ///
86    /// # Examples
87    ///
88    /// ```ignore
89    /// use std::sync::Arc;
90    /// use wp_model_core::model::{FieldStorage, Field, Value, DataType};
91    ///
92    /// let field = Field::new(DataType::Digit, "num", Value::from(42));
93    /// let storage = FieldStorage::from_owned(field);
94    /// let owned = storage.into_owned();
95    ///
96    /// assert_eq!(owned.get_name(), "num");
97    /// ```
98    pub fn into_owned(self) -> Field<Value> {
99        match self {
100            FieldStorage::Shared(arc) => {
101                // Try to unwrap if this is the only reference, otherwise clone
102                Arc::try_unwrap(arc).unwrap_or_else(|arc| (*arc).clone())
103            }
104            FieldStorage::Owned(field) => field,
105        }
106    }
107
108    /// Create Shared variant from owned field.
109    ///
110    /// # Examples
111    ///
112    /// ```ignore
113    /// use wp_model_core::model::{FieldStorage, Field, Value, DataType};
114    ///
115    /// let field = Field::new(DataType::Chars, "name", Value::from("Alice"));
116    /// let storage = FieldStorage::from_shared(field);
117    ///
118    /// assert!(storage.is_shared());
119    /// ```
120    pub fn from_shared(field: Field<Value>) -> Self {
121        FieldStorage::Shared(Arc::new(field))
122    }
123
124    /// Create Owned variant from owned field.
125    ///
126    /// # Examples
127    ///
128    /// ```ignore
129    /// use wp_model_core::model::{FieldStorage, Field, Value, DataType};
130    ///
131    /// let field = Field::new(DataType::Digit, "count", Value::from(10));
132    /// let storage = FieldStorage::from_owned(field);
133    ///
134    /// assert!(!storage.is_shared());
135    /// ```
136    pub fn from_owned(field: Field<Value>) -> Self {
137        FieldStorage::Owned(field)
138    }
139
140    /// Check if this is a Shared variant.
141    ///
142    /// # Examples
143    ///
144    /// ```ignore
145    /// use wp_model_core::model::{FieldStorage, Field, Value, DataType};
146    ///
147    /// let field = Field::new(DataType::Chars, "test", Value::from("data"));
148    /// let shared = FieldStorage::from_shared(field.clone());
149    /// let owned = FieldStorage::from_owned(field);
150    ///
151    /// assert!(shared.is_shared());
152    /// assert!(!owned.is_shared());
153    /// ```
154    #[inline]
155    pub fn is_shared(&self) -> bool {
156        matches!(self, FieldStorage::Shared(_))
157    }
158
159    /// Get Arc reference count (for debugging/diagnostics).
160    ///
161    /// Returns `Some(count)` for Shared variant, `None` for Owned variant.
162    ///
163    /// # Examples
164    ///
165    /// ```ignore
166    /// use wp_model_core::model::{FieldStorage, Field, Value, DataType};
167    ///
168    /// let field = Field::new(DataType::Digit, "x", Value::from(1));
169    /// let shared = FieldStorage::from_shared(field);
170    ///
171    /// assert_eq!(shared.shared_count(), Some(1));
172    ///
173    /// let shared2 = shared.clone();
174    /// assert_eq!(shared.shared_count(), Some(2));
175    /// ```
176    pub fn shared_count(&self) -> Option<usize> {
177        match self {
178            FieldStorage::Shared(arc) => Some(Arc::strong_count(arc)),
179            FieldStorage::Owned(_) => None,
180        }
181    }
182
183    /// Check if this is an Owned variant.
184    ///
185    /// # Examples
186    ///
187    /// ```ignore
188    /// use wp_model_core::model::{FieldStorage, Field, Value, DataType};
189    ///
190    /// let field = Field::new(DataType::Chars, "test", Value::from("data"));
191    /// let owned = FieldStorage::from_owned(field);
192    /// assert!(owned.is_owned());
193    /// ```
194    #[inline]
195    pub fn is_owned(&self) -> bool {
196        matches!(self, FieldStorage::Owned(_))
197    }
198
199    /// Get a mutable reference to the underlying field.
200    ///
201    /// For the `Shared` variant, this converts to `Owned` first (clone-on-write).
202    /// For the `Owned` variant, returns a direct mutable reference.
203    ///
204    /// # Examples
205    ///
206    /// ```ignore
207    /// use wp_model_core::model::{FieldStorage, Field, Value, DataType};
208    ///
209    /// let mut storage = FieldStorage::from_owned(Field::from_chars("name", "Alice"));
210    /// storage.as_field_mut().set_name("renamed");
211    /// assert_eq!(storage.as_field().get_name(), "renamed");
212    /// ```
213    pub fn as_field_mut(&mut self) -> &mut Field<Value> {
214        if let FieldStorage::Shared(_) = self {
215            let old = std::mem::replace(
216                self,
217                FieldStorage::Owned(Field::new(DataType::Ignore, "", Value::from(false))),
218            );
219            *self = FieldStorage::Owned(old.into_owned());
220        }
221        match self {
222            FieldStorage::Owned(field) => field,
223            FieldStorage::Shared(_) => unreachable!(),
224        }
225    }
226}
227
228// Implement Display by delegating to inner field
229impl Display for FieldStorage {
230    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
231        self.as_field().fmt(f)
232    }
233}
234
235// Implement PartialEq by comparing the underlying fields
236impl PartialEq for FieldStorage {
237    fn eq(&self, other: &Self) -> bool {
238        self.as_field().eq(other.as_field())
239    }
240}
241
242impl Eq for FieldStorage {}
243
244// Serialize: Transparently serialize as Field<Value>
245impl Serialize for FieldStorage {
246    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
247    where
248        S: Serializer,
249    {
250        // Both variants serialize the same way (as Field<Value>)
251        self.as_field().serialize(serializer)
252    }
253}
254
255// Deserialize: Always deserialize to Owned variant
256impl<'de> Deserialize<'de> for FieldStorage {
257    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
258    where
259        D: Deserializer<'de>,
260    {
261        // Deserialize as Field<Value> and wrap in Owned variant
262        Field::<Value>::deserialize(deserializer).map(FieldStorage::Owned)
263    }
264}
265
266// Implement RecordItem trait by delegating to the inner field
267impl RecordItem for FieldStorage {
268    fn get_name(&self) -> &str {
269        self.as_field().get_name()
270    }
271
272    fn get_meta(&self) -> &DataType {
273        self.as_field().get_meta()
274    }
275
276    fn get_value(&self) -> &Value {
277        self.as_field().get_value()
278    }
279
280    fn get_value_mut(&mut self) -> &mut Value {
281        self.as_field_mut().get_value_mut()
282    }
283}
284
285// Implement RecordItemFactory trait
286impl RecordItemFactory for FieldStorage {
287    fn from_digit<S: Into<FNameStr>>(name: S, val: i64) -> Self {
288        FieldStorage::Owned(Field::from_digit(name, val))
289    }
290
291    fn from_ip<S: Into<FNameStr>>(name: S, ip: IpAddr) -> Self {
292        FieldStorage::Owned(Field::from_ip(name, ip))
293    }
294
295    fn from_chars<N: Into<FNameStr>, Val: Into<FValueStr>>(name: N, val: Val) -> Self {
296        FieldStorage::Owned(Field::from_chars(name, val))
297    }
298}
299
300// Implement LevelFormatAble by delegating to inner field
301impl LevelFormatAble for FieldStorage {
302    fn level_fmt(&self, f: &mut Formatter<'_>, level: usize) -> std::fmt::Result {
303        self.as_field().level_fmt(f, level)
304    }
305}
306
307// 自动转换(降低迁移成本)
308impl From<Field<Value>> for FieldStorage {
309    fn from(field: Field<Value>) -> Self {
310        FieldStorage::Owned(field)
311    }
312}
313
314impl From<Arc<Field<Value>>> for FieldStorage {
315    fn from(arc: Arc<Field<Value>>) -> Self {
316        FieldStorage::Shared(arc)
317    }
318}
319
320#[cfg(test)]
321mod tests {
322    use super::*;
323    use crate::model::DataType;
324
325    #[test]
326    fn test_field_storage_shared_variant() {
327        let field = Field::new(DataType::Chars, "test", Value::from("hello"));
328        let storage = FieldStorage::Shared(Arc::new(field.clone()));
329
330        // as_field returns correct reference
331        assert_eq!(storage.as_field().get_name(), "test");
332        assert!(storage.is_shared());
333        assert_eq!(storage.shared_count(), Some(1));
334
335        // Clone Shared variant only increments reference count
336        let storage2 = storage.clone();
337        assert_eq!(storage.shared_count(), Some(2));
338        assert_eq!(storage2.shared_count(), Some(2));
339    }
340
341    #[test]
342    fn test_field_storage_owned_variant() {
343        let field = Field::new(DataType::Digit, "test", Value::from(42));
344        let storage = FieldStorage::Owned(field);
345
346        assert_eq!(storage.as_field().get_name(), "test");
347        assert!(!storage.is_shared());
348        assert_eq!(storage.shared_count(), None);
349    }
350
351    #[test]
352    fn test_into_owned() {
353        // Shared variant
354        let field1 = Field::new(DataType::Chars, "shared_field", Value::from("value"));
355        let storage1 = FieldStorage::Shared(Arc::new(field1));
356        let owned1 = storage1.into_owned();
357        assert_eq!(owned1.get_name(), "shared_field");
358
359        // Owned variant
360        let field2 = Field::new(DataType::Digit, "owned_field", Value::from(123));
361        let storage2 = FieldStorage::Owned(field2);
362        let owned2 = storage2.into_owned();
363        assert_eq!(owned2.get_name(), "owned_field");
364    }
365
366    #[test]
367    fn test_from_shared() {
368        let field = Field::new(DataType::Chars, "name", Value::from("Alice"));
369        let storage = FieldStorage::from_shared(field);
370
371        assert!(storage.is_shared());
372        assert_eq!(storage.as_field().get_name(), "name");
373    }
374
375    #[test]
376    fn test_from_owned() {
377        let field = Field::new(DataType::Digit, "count", Value::from(10));
378        let storage = FieldStorage::from_owned(field);
379
380        assert!(!storage.is_shared());
381        assert_eq!(storage.as_field().get_name(), "count");
382    }
383
384    #[test]
385    fn test_display() {
386        let field = Field::new(DataType::Digit, "num", Value::from(42));
387        let storage = FieldStorage::from_owned(field);
388
389        let display = format!("{}", storage);
390        assert!(display.contains("42"));
391    }
392
393    #[test]
394    fn test_equality() {
395        let field1 = Field::new(DataType::Chars, "test", Value::from("value"));
396        let field2 = Field::new(DataType::Chars, "test", Value::from("value"));
397        let field3 = Field::new(DataType::Chars, "test", Value::from("different"));
398
399        let shared1 = FieldStorage::from_shared(field1.clone());
400        let owned1 = FieldStorage::from_owned(field1);
401        let shared2 = FieldStorage::from_shared(field2);
402        let owned3 = FieldStorage::from_owned(field3);
403
404        // Same content should be equal regardless of storage type
405        assert_eq!(shared1, owned1);
406        assert_eq!(shared1, shared2);
407
408        // Different content should not be equal
409        assert_ne!(shared1, owned3);
410    }
411
412    #[test]
413    fn test_serde_serialization() {
414        let field1 = Field::new(DataType::Chars, "f1", Value::from("shared"));
415        let field2 = Field::new(DataType::Digit, "f2", Value::from(99));
416
417        let shared = FieldStorage::from_shared(field1);
418        let owned = FieldStorage::from_owned(field2);
419
420        // Serialize
421        let json_shared = serde_json::to_string(&shared).unwrap();
422        let json_owned = serde_json::to_string(&owned).unwrap();
423
424        // Deserialize (should always get Owned variant)
425        let deserialized_shared: FieldStorage = serde_json::from_str(&json_shared).unwrap();
426        let deserialized_owned: FieldStorage = serde_json::from_str(&json_owned).unwrap();
427
428        // Verify values are correct
429        assert_eq!(deserialized_shared.as_field().get_name(), "f1");
430        assert_eq!(deserialized_owned.as_field().get_name(), "f2");
431
432        // Verify both are Owned variant after deserialization
433        assert!(!deserialized_shared.is_shared());
434        assert!(!deserialized_owned.is_shared());
435    }
436
437    #[test]
438    fn test_clone_performance_difference() {
439        // This is more of a documentation test showing the usage pattern
440        use crate::model::FValueStr;
441        let large_str = FValueStr::from("x".repeat(1000));
442        let field = Field::new(DataType::Chars, "large", Value::from(large_str));
443
444        // Shared: cheap clone
445        let shared = FieldStorage::from_shared(field.clone());
446        let _shared2 = shared.clone();
447        assert_eq!(shared.shared_count(), Some(2));
448
449        // Owned: deep clone
450        let owned = FieldStorage::from_owned(field);
451        let _owned2 = owned.clone();
452        assert!(owned.shared_count().is_none());
453    }
454
455    #[test]
456    fn test_from_arc_to_fieldstorage() {
457        let field = Field::new(DataType::Chars, "name", Value::from("Alice"));
458        let arc = Arc::new(field);
459        let storage: FieldStorage = arc.into();
460
461        assert!(storage.is_shared());
462        assert_eq!(storage.as_field().get_name(), "name");
463    }
464
465    #[test]
466    fn test_is_owned() {
467        let field = Field::new(DataType::Digit, "x", Value::from(1));
468        let owned = FieldStorage::from_owned(field.clone());
469        let shared = FieldStorage::from_shared(field);
470
471        assert!(owned.is_owned());
472        assert!(!shared.is_owned());
473    }
474
475    #[test]
476    fn test_as_field_mut_owned() {
477        let mut storage = FieldStorage::from_owned(Field::from_chars("name", "Alice"));
478        storage.as_field_mut().set_name("renamed");
479        assert_eq!(storage.as_field().get_name(), "renamed");
480        assert!(storage.is_owned());
481    }
482
483    #[test]
484    fn test_as_field_mut_shared() {
485        let field = Field::from_chars("name", "Alice");
486        let mut storage = FieldStorage::from_shared(field);
487        assert!(storage.is_shared());
488
489        // Mutating converts Shared to Owned
490        storage.as_field_mut().set_name("renamed");
491        assert!(storage.is_owned());
492        assert_eq!(storage.as_field().get_name(), "renamed");
493    }
494}