1use indexmap::IndexMap;
8use std::borrow::Cow;
9use std::fmt;
10use std::hash::{Hash, Hasher};
11
12#[derive(Debug, Clone, PartialEq, Default)]
14pub enum BorrowedValue<'a> {
15 #[default]
17 Null,
18 Bool(bool),
20 Int(i64),
22 Float(f64),
24 String(Cow<'a, str>),
26 Sequence(Vec<BorrowedValue<'a>>),
28 Mapping(IndexMap<BorrowedValue<'a>, BorrowedValue<'a>>),
30}
31
32impl<'a> BorrowedValue<'a> {
33 pub const fn null() -> Self {
35 Self::Null
36 }
37
38 pub const fn bool(b: bool) -> Self {
40 Self::Bool(b)
41 }
42
43 pub const fn int(i: i64) -> Self {
45 Self::Int(i)
46 }
47
48 pub const fn float(f: f64) -> Self {
50 Self::Float(f)
51 }
52
53 pub const fn borrowed_string(s: &'a str) -> Self {
55 Self::String(Cow::Borrowed(s))
56 }
57
58 pub fn owned_string(s: String) -> Self {
60 Self::String(Cow::Owned(s))
61 }
62
63 pub const fn string(s: Cow<'a, str>) -> Self {
65 Self::String(s)
66 }
67
68 pub const fn sequence() -> Self {
70 Self::Sequence(Vec::new())
71 }
72
73 pub const fn sequence_with(values: Vec<Self>) -> Self {
75 Self::Sequence(values)
76 }
77
78 pub fn mapping() -> Self {
80 Self::Mapping(IndexMap::new())
81 }
82
83 pub fn mapping_with(pairs: Vec<(Self, Self)>) -> Self {
85 let mut map = IndexMap::new();
86 for (key, value) in pairs {
87 map.insert(key, value);
88 }
89 Self::Mapping(map)
90 }
91
92 pub const fn type_name(&self) -> &'static str {
94 match self {
95 Self::Null => "null",
96 Self::Bool(_) => "bool",
97 Self::Int(_) => "int",
98 Self::Float(_) => "float",
99 Self::String(_) => "string",
100 Self::Sequence(_) => "sequence",
101 Self::Mapping(_) => "mapping",
102 }
103 }
104
105 pub const fn is_null(&self) -> bool {
107 matches!(self, Self::Null)
108 }
109
110 pub const fn is_bool(&self) -> bool {
112 matches!(self, Self::Bool(_))
113 }
114
115 pub const fn is_int(&self) -> bool {
117 matches!(self, Self::Int(_))
118 }
119
120 pub const fn is_float(&self) -> bool {
122 matches!(self, Self::Float(_))
123 }
124
125 pub const fn is_string(&self) -> bool {
127 matches!(self, Self::String(_))
128 }
129
130 pub const fn is_sequence(&self) -> bool {
132 matches!(self, Self::Sequence(_))
133 }
134
135 pub const fn is_mapping(&self) -> bool {
137 matches!(self, Self::Mapping(_))
138 }
139
140 pub const fn as_bool(&self) -> Option<bool> {
142 if let Self::Bool(b) = self {
143 Some(*b)
144 } else {
145 None
146 }
147 }
148
149 pub const fn as_int(&self) -> Option<i64> {
151 if let Self::Int(i) = self {
152 Some(*i)
153 } else {
154 None
155 }
156 }
157
158 pub const fn as_float(&self) -> Option<f64> {
160 match self {
161 Self::Float(f) => Some(*f),
162 Self::Int(i) => Some(*i as f64),
163 _ => None,
164 }
165 }
166
167 pub fn as_str(&self) -> Option<&str> {
169 if let Self::String(s) = self {
170 Some(s.as_ref())
171 } else {
172 None
173 }
174 }
175
176 pub const fn as_sequence(&self) -> Option<&Vec<BorrowedValue<'a>>> {
178 if let Self::Sequence(seq) = self {
179 Some(seq)
180 } else {
181 None
182 }
183 }
184
185 pub fn as_sequence_mut(&mut self) -> Option<&mut Vec<BorrowedValue<'a>>> {
187 if let Self::Sequence(seq) = self {
188 Some(seq)
189 } else {
190 None
191 }
192 }
193
194 pub const fn as_mapping(&self) -> Option<&IndexMap<BorrowedValue<'a>, BorrowedValue<'a>>> {
196 if let Self::Mapping(map) = self {
197 Some(map)
198 } else {
199 None
200 }
201 }
202
203 pub fn as_mapping_mut(
205 &mut self,
206 ) -> Option<&mut IndexMap<BorrowedValue<'a>, BorrowedValue<'a>>> {
207 if let Self::Mapping(map) = self {
208 Some(map)
209 } else {
210 None
211 }
212 }
213
214 pub fn into_owned(self) -> BorrowedValue<'static> {
216 match self {
217 Self::Null => BorrowedValue::Null,
218 Self::Bool(b) => BorrowedValue::Bool(b),
219 Self::Int(i) => BorrowedValue::Int(i),
220 Self::Float(f) => BorrowedValue::Float(f),
221 Self::String(s) => BorrowedValue::String(Cow::Owned(s.into_owned())),
222 Self::Sequence(seq) => {
223 BorrowedValue::Sequence(seq.into_iter().map(|v| v.into_owned()).collect())
224 }
225 Self::Mapping(map) => BorrowedValue::Mapping(
226 map.into_iter()
227 .map(|(k, v)| (k.into_owned(), v.into_owned()))
228 .collect(),
229 ),
230 }
231 }
232
233 pub fn clone_if_needed(&self) -> Self {
235 match self {
236 Self::String(Cow::Borrowed(s)) => Self::String(Cow::Borrowed(s)),
237 _ => self.clone(),
238 }
239 }
240}
241
242impl<'a> fmt::Display for BorrowedValue<'a> {
243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 match self {
245 Self::Null => write!(f, "null"),
246 Self::Bool(b) => write!(f, "{}", b),
247 Self::Int(i) => write!(f, "{}", i),
248 Self::Float(fl) => write!(f, "{}", fl),
249 Self::String(s) => write!(f, "{}", s),
250 Self::Sequence(seq) => {
251 write!(f, "[")?;
252 for (i, item) in seq.iter().enumerate() {
253 if i > 0 {
254 write!(f, ", ")?;
255 }
256 write!(f, "{}", item)?;
257 }
258 write!(f, "]")
259 }
260 Self::Mapping(map) => {
261 write!(f, "{{")?;
262 for (i, (key, value)) in map.iter().enumerate() {
263 if i > 0 {
264 write!(f, ", ")?;
265 }
266 write!(f, "{}: {}", key, value)?;
267 }
268 write!(f, "}}")
269 }
270 }
271 }
272}
273
274impl<'a> Hash for BorrowedValue<'a> {
275 fn hash<H: Hasher>(&self, state: &mut H) {
276 match self {
277 Self::Null => 0.hash(state),
278 Self::Bool(b) => {
279 1.hash(state);
280 b.hash(state);
281 }
282 Self::Int(i) => {
283 2.hash(state);
284 i.hash(state);
285 }
286 Self::Float(f) => {
287 3.hash(state);
288 f.to_bits().hash(state);
289 }
290 Self::String(s) => {
291 4.hash(state);
292 s.hash(state);
293 }
294 Self::Sequence(seq) => {
295 5.hash(state);
296 seq.hash(state);
297 }
298 Self::Mapping(_) => {
299 6.hash(state);
300 }
303 }
304 }
305}
306
307impl<'a> Eq for BorrowedValue<'a> {}
308
309impl<'a> From<crate::Value> for BorrowedValue<'a> {
311 fn from(value: crate::Value) -> Self {
312 match value {
313 crate::Value::Null => Self::Null,
314 crate::Value::Bool(b) => Self::Bool(b),
315 crate::Value::Int(i) => Self::Int(i),
316 crate::Value::Float(f) => Self::Float(f),
317 crate::Value::String(s) => Self::String(Cow::Owned(s)),
318 crate::Value::Sequence(seq) => {
319 Self::Sequence(seq.into_iter().map(Into::into).collect())
320 }
321 crate::Value::Mapping(map) => {
322 Self::Mapping(map.into_iter().map(|(k, v)| (k.into(), v.into())).collect())
323 }
324 }
325 }
326}
327
328impl From<BorrowedValue<'_>> for crate::Value {
330 fn from(value: BorrowedValue<'_>) -> Self {
331 match value {
332 BorrowedValue::Null => Self::Null,
333 BorrowedValue::Bool(b) => Self::Bool(b),
334 BorrowedValue::Int(i) => Self::Int(i),
335 BorrowedValue::Float(f) => Self::Float(f),
336 BorrowedValue::String(s) => Self::String(s.into_owned()),
337 BorrowedValue::Sequence(seq) => {
338 Self::Sequence(seq.into_iter().map(Into::into).collect())
339 }
340 BorrowedValue::Mapping(map) => {
341 Self::Mapping(map.into_iter().map(|(k, v)| (k.into(), v.into())).collect())
342 }
343 }
344 }
345}
346
347#[cfg(test)]
348mod tests {
349 use super::*;
350
351 #[test]
352 fn test_borrowed_string() {
353 let s = "hello world";
354 let value = BorrowedValue::borrowed_string(s);
355 assert_eq!(value.as_str(), Some("hello world"));
356
357 if let BorrowedValue::String(cow) = &value {
359 assert!(matches!(cow, Cow::Borrowed(_)));
360 }
361 }
362
363 #[test]
364 fn test_owned_string() {
365 let value = BorrowedValue::owned_string("hello".to_string());
366 assert_eq!(value.as_str(), Some("hello"));
367
368 if let BorrowedValue::String(cow) = &value {
370 assert!(matches!(cow, Cow::Owned(_)));
371 }
372 }
373
374 #[test]
375 fn test_into_owned() {
376 let s = "test";
377 let borrowed = BorrowedValue::borrowed_string(s);
378 let owned: BorrowedValue<'static> = borrowed.into_owned();
379
380 if let BorrowedValue::String(cow) = &owned {
382 assert!(matches!(cow, Cow::Owned(_)));
383 }
384 }
385
386 #[test]
387 fn test_zero_copy_mapping() {
388 let key = "key";
389 let value = "value";
390
391 let map = BorrowedValue::mapping_with(vec![(
392 BorrowedValue::borrowed_string(key),
393 BorrowedValue::borrowed_string(value),
394 )]);
395
396 assert!(map.is_mapping());
397 if let BorrowedValue::Mapping(m) = &map {
398 assert_eq!(m.len(), 1);
399 }
400 }
401}