rust_yaml/
zero_copy_value.rs

1//! Optimized YAML value representation with reduced allocations
2//!
3//! This module provides an optimized Value type that reduces cloning
4//! and allocations through careful use of reference counting and
5//! copy-on-write semantics.
6
7use indexmap::IndexMap;
8use std::fmt;
9use std::rc::Rc;
10
11/// An optimized YAML value that minimizes allocations
12#[derive(Debug, Clone, PartialEq)]
13pub enum OptimizedValue {
14    /// Null value
15    Null,
16    /// Boolean value
17    Bool(bool),
18    /// Integer value
19    Int(i64),
20    /// Float value
21    Float(f64),
22    /// String value (using Rc for cheap cloning)
23    String(Rc<String>),
24    /// Sequence value (using Rc for cheap cloning)
25    Sequence(Rc<Vec<OptimizedValue>>),
26    /// Mapping value (using Rc for cheap cloning)
27    Mapping(Rc<IndexMap<OptimizedValue, OptimizedValue>>),
28}
29
30impl OptimizedValue {
31    /// Create a null value
32    pub const fn null() -> Self {
33        Self::Null
34    }
35
36    /// Create a boolean value
37    pub const fn bool(b: bool) -> Self {
38        Self::Bool(b)
39    }
40
41    /// Create an integer value
42    pub const fn int(i: i64) -> Self {
43        Self::Int(i)
44    }
45
46    /// Create a float value
47    pub const fn float(f: f64) -> Self {
48        Self::Float(f)
49    }
50
51    /// Create a string value
52    pub fn string(s: impl Into<String>) -> Self {
53        Self::String(Rc::new(s.into()))
54    }
55
56    /// Create an empty sequence
57    pub fn sequence() -> Self {
58        Self::Sequence(Rc::new(Vec::new()))
59    }
60
61    /// Create a sequence with values
62    pub fn sequence_with(values: Vec<Self>) -> Self {
63        Self::Sequence(Rc::new(values))
64    }
65
66    /// Create an empty mapping
67    pub fn mapping() -> Self {
68        Self::Mapping(Rc::new(IndexMap::new()))
69    }
70
71    /// Create a mapping with key-value pairs
72    pub fn mapping_with(pairs: Vec<(Self, Self)>) -> Self {
73        let mut map = IndexMap::new();
74        for (key, value) in pairs {
75            map.insert(key, value);
76        }
77        Self::Mapping(Rc::new(map))
78    }
79
80    /// Get a reference to the string if this is a string value
81    pub fn as_str(&self) -> Option<&str> {
82        if let Self::String(s) = self {
83            Some(s.as_str())
84        } else {
85            None
86        }
87    }
88
89    /// Get a reference to the sequence if this is a sequence value
90    pub fn as_sequence(&self) -> Option<&[OptimizedValue]> {
91        if let Self::Sequence(seq) = self {
92            Some(seq.as_slice())
93        } else {
94            None
95        }
96    }
97
98    /// Get a reference to the mapping if this is a mapping value
99    pub fn as_mapping(&self) -> Option<&IndexMap<OptimizedValue, OptimizedValue>> {
100        if let Self::Mapping(map) = self {
101            Some(map.as_ref())
102        } else {
103            None
104        }
105    }
106
107    /// Convert from regular Value
108    pub fn from_value(value: crate::Value) -> Self {
109        match value {
110            crate::Value::Null => Self::Null,
111            crate::Value::Bool(b) => Self::Bool(b),
112            crate::Value::Int(i) => Self::Int(i),
113            crate::Value::Float(f) => Self::Float(f),
114            crate::Value::String(s) => Self::String(Rc::new(s)),
115            crate::Value::Sequence(seq) => {
116                Self::Sequence(Rc::new(seq.into_iter().map(Self::from_value).collect()))
117            }
118            crate::Value::Mapping(map) => Self::Mapping(Rc::new(
119                map.into_iter()
120                    .map(|(k, v)| (Self::from_value(k), Self::from_value(v)))
121                    .collect(),
122            )),
123        }
124    }
125
126    /// Convert to regular Value
127    pub fn to_value(&self) -> crate::Value {
128        match self {
129            Self::Null => crate::Value::Null,
130            Self::Bool(b) => crate::Value::Bool(*b),
131            Self::Int(i) => crate::Value::Int(*i),
132            Self::Float(f) => crate::Value::Float(*f),
133            Self::String(s) => crate::Value::String((**s).clone()),
134            Self::Sequence(seq) => {
135                crate::Value::Sequence(seq.iter().map(|v| v.to_value()).collect())
136            }
137            Self::Mapping(map) => crate::Value::Mapping(
138                map.iter()
139                    .map(|(k, v)| (k.to_value(), v.to_value()))
140                    .collect(),
141            ),
142        }
143    }
144}
145
146impl fmt::Display for OptimizedValue {
147    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148        match self {
149            Self::Null => write!(f, "null"),
150            Self::Bool(b) => write!(f, "{}", b),
151            Self::Int(i) => write!(f, "{}", i),
152            Self::Float(fl) => write!(f, "{}", fl),
153            Self::String(s) => write!(f, "{}", s),
154            Self::Sequence(seq) => {
155                write!(f, "[")?;
156                for (i, item) in seq.iter().enumerate() {
157                    if i > 0 {
158                        write!(f, ", ")?;
159                    }
160                    write!(f, "{}", item)?;
161                }
162                write!(f, "]")
163            }
164            Self::Mapping(map) => {
165                write!(f, "{{")?;
166                for (i, (key, value)) in map.iter().enumerate() {
167                    if i > 0 {
168                        write!(f, ", ")?;
169                    }
170                    write!(f, "{}: {}", key, value)?;
171                }
172                write!(f, "}}")
173            }
174        }
175    }
176}
177
178impl std::hash::Hash for OptimizedValue {
179    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
180        match self {
181            Self::Null => 0.hash(state),
182            Self::Bool(b) => {
183                1.hash(state);
184                b.hash(state);
185            }
186            Self::Int(i) => {
187                2.hash(state);
188                i.hash(state);
189            }
190            Self::Float(f) => {
191                3.hash(state);
192                f.to_bits().hash(state);
193            }
194            Self::String(s) => {
195                4.hash(state);
196                s.hash(state);
197            }
198            Self::Sequence(seq) => {
199                5.hash(state);
200                seq.len().hash(state);
201                for item in seq.iter() {
202                    item.hash(state);
203                }
204            }
205            Self::Mapping(_) => {
206                6.hash(state);
207                // Mapping order is deterministic but we can't hash directly
208            }
209        }
210    }
211}
212
213impl Eq for OptimizedValue {}
214
215#[cfg(test)]
216mod tests {
217    use super::*;
218
219    #[test]
220    fn test_rc_string_cloning() {
221        let value1 = OptimizedValue::string("hello world");
222        let value2 = value1.clone();
223
224        // Both should point to the same Rc
225        if let (OptimizedValue::String(s1), OptimizedValue::String(s2)) = (&value1, &value2) {
226            assert!(Rc::ptr_eq(s1, s2));
227        }
228    }
229
230    #[test]
231    fn test_rc_sequence_cloning() {
232        let value1 =
233            OptimizedValue::sequence_with(vec![OptimizedValue::int(1), OptimizedValue::int(2)]);
234        let value2 = value1.clone();
235
236        // Both should point to the same Rc
237        if let (OptimizedValue::Sequence(s1), OptimizedValue::Sequence(s2)) = (&value1, &value2) {
238            assert!(Rc::ptr_eq(s1, s2));
239        }
240    }
241
242    #[test]
243    fn test_conversion_roundtrip() {
244        let original = crate::Value::Mapping(indexmap::indexmap! {
245            crate::Value::String("key".to_string()) => crate::Value::Int(42),
246        });
247
248        let optimized = OptimizedValue::from_value(original.clone());
249        let converted_back = optimized.to_value();
250
251        assert_eq!(original, converted_back);
252    }
253}