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
184// Implement Display by delegating to inner field
185impl Display for FieldStorage {
186    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
187        self.as_field().fmt(f)
188    }
189}
190
191// Implement PartialEq by comparing the underlying fields
192impl PartialEq for FieldStorage {
193    fn eq(&self, other: &Self) -> bool {
194        self.as_field().eq(other.as_field())
195    }
196}
197
198impl Eq for FieldStorage {}
199
200// Serialize: Transparently serialize as Field<Value>
201impl Serialize for FieldStorage {
202    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
203    where
204        S: Serializer,
205    {
206        // Both variants serialize the same way (as Field<Value>)
207        self.as_field().serialize(serializer)
208    }
209}
210
211// Deserialize: Always deserialize to Owned variant
212impl<'de> Deserialize<'de> for FieldStorage {
213    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
214    where
215        D: Deserializer<'de>,
216    {
217        // Deserialize as Field<Value> and wrap in Owned variant
218        Field::<Value>::deserialize(deserializer).map(FieldStorage::Owned)
219    }
220}
221
222// Implement RecordItem trait by delegating to the inner field
223impl RecordItem for FieldStorage {
224    fn get_name(&self) -> &str {
225        self.as_field().get_name()
226    }
227
228    fn get_meta(&self) -> &DataType {
229        self.as_field().get_meta()
230    }
231
232    fn get_value(&self) -> &Value {
233        self.as_field().get_value()
234    }
235
236    fn get_value_mut(&mut self) -> &mut Value {
237        match self {
238            FieldStorage::Shared(arc) => {
239                // If there are multiple references, we need to clone to get a mutable version
240                // This converts Shared to Owned variant
241                let field = Arc::try_unwrap(std::mem::replace(
242                    arc,
243                    Arc::new(Field::new(DataType::Ignore, "", Value::from(false))),
244                ))
245                .unwrap_or_else(|arc| (*arc).clone());
246                *self = FieldStorage::Owned(field);
247                match self {
248                    FieldStorage::Owned(f) => f.get_value_mut(),
249                    _ => unreachable!(),
250                }
251            }
252            FieldStorage::Owned(field) => field.get_value_mut(),
253        }
254    }
255}
256
257// Implement RecordItemFactory trait
258impl RecordItemFactory for FieldStorage {
259    fn from_digit<S: Into<FNameStr>>(name: S, val: i64) -> Self {
260        FieldStorage::Owned(Field::from_digit(name, val))
261    }
262
263    fn from_ip<S: Into<FNameStr>>(name: S, ip: IpAddr) -> Self {
264        FieldStorage::Owned(Field::from_ip(name, ip))
265    }
266
267    fn from_chars<N: Into<FNameStr>, Val: Into<FValueStr>>(name: N, val: Val) -> Self {
268        FieldStorage::Owned(Field::from_chars(name, val))
269    }
270}
271
272// Implement LevelFormatAble by delegating to inner field
273impl LevelFormatAble for FieldStorage {
274    fn level_fmt(&self, f: &mut Formatter<'_>, level: usize) -> std::fmt::Result {
275        self.as_field().level_fmt(f, level)
276    }
277}
278
279// 自动转换(降低迁移成本)
280impl From<Field<Value>> for FieldStorage {
281    fn from(field: Field<Value>) -> Self {
282        FieldStorage::Owned(field)
283    }
284}
285
286#[cfg(test)]
287mod tests {
288    use super::*;
289    use crate::model::DataType;
290
291    #[test]
292    fn test_field_storage_shared_variant() {
293        let field = Field::new(DataType::Chars, "test", Value::from("hello"));
294        let storage = FieldStorage::Shared(Arc::new(field.clone()));
295
296        // as_field returns correct reference
297        assert_eq!(storage.as_field().get_name(), "test");
298        assert!(storage.is_shared());
299        assert_eq!(storage.shared_count(), Some(1));
300
301        // Clone Shared variant only increments reference count
302        let storage2 = storage.clone();
303        assert_eq!(storage.shared_count(), Some(2));
304        assert_eq!(storage2.shared_count(), Some(2));
305    }
306
307    #[test]
308    fn test_field_storage_owned_variant() {
309        let field = Field::new(DataType::Digit, "test", Value::from(42));
310        let storage = FieldStorage::Owned(field);
311
312        assert_eq!(storage.as_field().get_name(), "test");
313        assert!(!storage.is_shared());
314        assert_eq!(storage.shared_count(), None);
315    }
316
317    #[test]
318    fn test_into_owned() {
319        // Shared variant
320        let field1 = Field::new(DataType::Chars, "shared_field", Value::from("value"));
321        let storage1 = FieldStorage::Shared(Arc::new(field1));
322        let owned1 = storage1.into_owned();
323        assert_eq!(owned1.get_name(), "shared_field");
324
325        // Owned variant
326        let field2 = Field::new(DataType::Digit, "owned_field", Value::from(123));
327        let storage2 = FieldStorage::Owned(field2);
328        let owned2 = storage2.into_owned();
329        assert_eq!(owned2.get_name(), "owned_field");
330    }
331
332    #[test]
333    fn test_from_shared() {
334        let field = Field::new(DataType::Chars, "name", Value::from("Alice"));
335        let storage = FieldStorage::from_shared(field);
336
337        assert!(storage.is_shared());
338        assert_eq!(storage.as_field().get_name(), "name");
339    }
340
341    #[test]
342    fn test_from_owned() {
343        let field = Field::new(DataType::Digit, "count", Value::from(10));
344        let storage = FieldStorage::from_owned(field);
345
346        assert!(!storage.is_shared());
347        assert_eq!(storage.as_field().get_name(), "count");
348    }
349
350    #[test]
351    fn test_display() {
352        let field = Field::new(DataType::Digit, "num", Value::from(42));
353        let storage = FieldStorage::from_owned(field);
354
355        let display = format!("{}", storage);
356        assert!(display.contains("42"));
357    }
358
359    #[test]
360    fn test_equality() {
361        let field1 = Field::new(DataType::Chars, "test", Value::from("value"));
362        let field2 = Field::new(DataType::Chars, "test", Value::from("value"));
363        let field3 = Field::new(DataType::Chars, "test", Value::from("different"));
364
365        let shared1 = FieldStorage::from_shared(field1.clone());
366        let owned1 = FieldStorage::from_owned(field1);
367        let shared2 = FieldStorage::from_shared(field2);
368        let owned3 = FieldStorage::from_owned(field3);
369
370        // Same content should be equal regardless of storage type
371        assert_eq!(shared1, owned1);
372        assert_eq!(shared1, shared2);
373
374        // Different content should not be equal
375        assert_ne!(shared1, owned3);
376    }
377
378    #[test]
379    fn test_serde_serialization() {
380        let field1 = Field::new(DataType::Chars, "f1", Value::from("shared"));
381        let field2 = Field::new(DataType::Digit, "f2", Value::from(99));
382
383        let shared = FieldStorage::from_shared(field1);
384        let owned = FieldStorage::from_owned(field2);
385
386        // Serialize
387        let json_shared = serde_json::to_string(&shared).unwrap();
388        let json_owned = serde_json::to_string(&owned).unwrap();
389
390        // Deserialize (should always get Owned variant)
391        let deserialized_shared: FieldStorage = serde_json::from_str(&json_shared).unwrap();
392        let deserialized_owned: FieldStorage = serde_json::from_str(&json_owned).unwrap();
393
394        // Verify values are correct
395        assert_eq!(deserialized_shared.as_field().get_name(), "f1");
396        assert_eq!(deserialized_owned.as_field().get_name(), "f2");
397
398        // Verify both are Owned variant after deserialization
399        assert!(!deserialized_shared.is_shared());
400        assert!(!deserialized_owned.is_shared());
401    }
402
403    #[test]
404    fn test_clone_performance_difference() {
405        // This is more of a documentation test showing the usage pattern
406        use crate::model::FValueStr;
407        let large_str = FValueStr::from("x".repeat(1000));
408        let field = Field::new(DataType::Chars, "large", Value::from(large_str));
409
410        // Shared: cheap clone
411        let shared = FieldStorage::from_shared(field.clone());
412        let _shared2 = shared.clone();
413        assert_eq!(shared.shared_count(), Some(2));
414
415        // Owned: deep clone
416        let owned = FieldStorage::from_owned(field);
417        let _owned2 = owned.clone();
418        assert!(owned.shared_count().is_none());
419    }
420}