1mod de;
4mod index;
5mod mapping;
6mod number;
7mod ser;
8
9use std::borrow::Cow;
10use std::fmt;
11
12use serde::{Deserialize, Deserializer, Serialize};
13
14use crate::{Error, Result};
15
16pub use index::Index;
17pub use mapping::{
18 Entry, IntoIter, IntoKeys, IntoValues, Iter, IterMut, Keys, Mapping, OccupiedEntry,
19 VacantEntry, Values, ValuesMut,
20};
21pub use number::Number;
22pub use ser::{Serializer, from_value, to_value};
23
24pub(crate) const TAGGED_VALUE_TOKEN: &str = "$yaml_rt::private::TaggedValue";
25
26pub type Sequence = Vec<Value>;
28
29#[derive(Clone, Default, PartialEq, PartialOrd, Hash)]
31pub enum Value {
32 #[default]
34 Null,
35 Bool(bool),
37 Number(Number),
39 String(String),
41 Sequence(Sequence),
43 Mapping(Mapping),
45 Tagged(Box<TaggedValue>),
47}
48
49impl Eq for Value {}
50
51impl fmt::Debug for Value {
52 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
53 match self {
54 Self::Null => formatter.write_str("Null"),
55 Self::Bool(value) => formatter.debug_tuple("Bool").field(value).finish(),
56 Self::Number(value) => formatter.debug_tuple("Number").field(value).finish(),
57 Self::String(value) => formatter.debug_tuple("String").field(value).finish(),
58 Self::Sequence(value) => formatter.debug_tuple("Sequence").field(value).finish(),
59 Self::Mapping(value) => formatter.debug_tuple("Mapping").field(value).finish(),
60 Self::Tagged(value) => formatter.debug_tuple("Tagged").field(value).finish(),
61 }
62 }
63}
64
65impl Value {
66 #[must_use]
68 pub fn get<I>(&self, index: I) -> Option<&Value>
69 where
70 I: Index,
71 {
72 index.index_into(self)
73 }
74
75 pub fn get_mut<I>(&mut self, index: I) -> Option<&mut Value>
77 where
78 I: Index,
79 {
80 index.index_into_mut(self)
81 }
82
83 pub(crate) fn untag_ref(&self) -> &Self {
84 let mut value = self;
85 while let Self::Tagged(tagged) = value {
86 value = &tagged.value;
87 }
88 value
89 }
90
91 pub(crate) fn untag_mut(&mut self) -> &mut Self {
92 let mut value = self;
93 while let Self::Tagged(tagged) = value {
94 value = &mut tagged.value;
95 }
96 value
97 }
98
99 #[must_use]
101 pub fn is_null(&self) -> bool {
102 matches!(self.untag_ref(), Self::Null)
103 }
104
105 #[must_use]
107 pub fn as_null(&self) -> Option<()> {
108 self.is_null().then_some(())
109 }
110
111 #[must_use]
113 pub fn is_bool(&self) -> bool {
114 self.as_bool().is_some()
115 }
116
117 #[must_use]
119 pub fn as_bool(&self) -> Option<bool> {
120 match self.untag_ref() {
121 Self::Bool(value) => Some(*value),
122 _ => None,
123 }
124 }
125
126 #[must_use]
128 pub fn is_number(&self) -> bool {
129 matches!(self.untag_ref(), Self::Number(_))
130 }
131
132 #[must_use]
134 pub fn is_i64(&self) -> bool {
135 self.as_i64().is_some()
136 }
137
138 #[must_use]
140 pub fn is_u64(&self) -> bool {
141 self.as_u64().is_some()
142 }
143
144 #[must_use]
146 pub fn is_f64(&self) -> bool {
147 matches!(self.untag_ref(), Self::Number(number) if number.is_f64())
148 }
149
150 #[must_use]
152 pub fn is_i128(&self) -> bool {
153 self.as_i128().is_some()
154 }
155
156 #[must_use]
158 pub fn is_u128(&self) -> bool {
159 self.as_u128().is_some()
160 }
161
162 #[must_use]
164 pub fn as_i64(&self) -> Option<i64> {
165 match self.untag_ref() {
166 Self::Number(number) => number.as_i64(),
167 _ => None,
168 }
169 }
170
171 #[must_use]
173 pub fn as_u64(&self) -> Option<u64> {
174 match self.untag_ref() {
175 Self::Number(number) => number.as_u64(),
176 _ => None,
177 }
178 }
179
180 #[must_use]
182 pub fn as_i128(&self) -> Option<i128> {
183 match self.untag_ref() {
184 Self::Number(number) => number.as_i128(),
185 _ => None,
186 }
187 }
188
189 #[must_use]
191 pub fn as_u128(&self) -> Option<u128> {
192 match self.untag_ref() {
193 Self::Number(number) => number.as_u128(),
194 _ => None,
195 }
196 }
197
198 #[must_use]
200 pub fn as_f64(&self) -> Option<f64> {
201 match self.untag_ref() {
202 Self::Number(number) => number.as_f64(),
203 _ => None,
204 }
205 }
206
207 #[must_use]
209 pub fn is_string(&self) -> bool {
210 self.as_str().is_some()
211 }
212
213 #[must_use]
215 pub fn as_str(&self) -> Option<&str> {
216 match self.untag_ref() {
217 Self::String(value) => Some(value),
218 _ => None,
219 }
220 }
221
222 #[must_use]
224 pub fn is_sequence(&self) -> bool {
225 self.as_sequence().is_some()
226 }
227
228 #[must_use]
230 pub fn as_sequence(&self) -> Option<&Sequence> {
231 match self.untag_ref() {
232 Self::Sequence(value) => Some(value),
233 _ => None,
234 }
235 }
236
237 pub fn as_sequence_mut(&mut self) -> Option<&mut Sequence> {
239 match self.untag_mut() {
240 Self::Sequence(value) => Some(value),
241 _ => None,
242 }
243 }
244
245 #[must_use]
247 pub fn is_mapping(&self) -> bool {
248 self.as_mapping().is_some()
249 }
250
251 #[must_use]
253 pub fn as_mapping(&self) -> Option<&Mapping> {
254 match self.untag_ref() {
255 Self::Mapping(value) => Some(value),
256 _ => None,
257 }
258 }
259
260 pub fn as_mapping_mut(&mut self) -> Option<&mut Mapping> {
262 match self.untag_mut() {
263 Self::Mapping(value) => Some(value),
264 _ => None,
265 }
266 }
267
268 pub fn apply_merge(&mut self) -> Result<()> {
275 match self {
276 Self::Sequence(values) => {
277 for value in values {
278 value.apply_merge()?;
279 }
280 }
281 Self::Mapping(mapping) => apply_mapping_merge(mapping)?,
282 Self::Tagged(tagged) => tagged.value.apply_merge()?,
283 Self::Null | Self::Bool(_) | Self::Number(_) | Self::String(_) => {}
284 }
285 Ok(())
286 }
287}
288
289fn apply_mapping_merge(mapping: &mut Mapping) -> Result<()> {
290 for (_, value) in &mut *mapping {
291 value.apply_merge()?;
292 }
293
294 let Some(position) = mapping
295 .entries
296 .iter()
297 .position(|(key, _)| matches!(key.untag_ref(), Value::String(key) if key == "<<"))
298 else {
299 return Ok(());
300 };
301
302 let (_, source) = mapping.entries.remove(position);
303 let explicit = std::mem::take(mapping);
304 let mut merged = Mapping::new();
305 merge_source(&mut merged, source.untag_ref())?;
306 for (key, value) in explicit {
307 merged.insert(key, value);
308 }
309 *mapping = merged;
310 Ok(())
311}
312
313fn merge_source(target: &mut Mapping, source: &Value) -> Result<()> {
314 match source {
315 Value::Mapping(mapping) => {
316 merge_mapping(target, mapping);
317 Ok(())
318 }
319 Value::Sequence(sequence) => {
320 for value in sequence {
321 let Value::Mapping(mapping) = value.untag_ref() else {
322 return Err(Error::message("expected a mapping in YAML merge sequence"));
323 };
324 merge_mapping(target, mapping);
325 }
326 Ok(())
327 }
328 _ => Err(Error::message(
329 "expected a mapping or sequence of mappings for YAML merge",
330 )),
331 }
332}
333
334fn merge_mapping(target: &mut Mapping, source: &Mapping) {
335 for (key, value) in source {
336 if !target.contains_key(key) {
337 target.insert(key.clone(), value.clone());
338 }
339 }
340}
341
342#[derive(Clone, Eq, Ord, PartialEq, PartialOrd, Hash)]
344pub struct Tag {
345 pub(crate) string: String,
346}
347
348impl Tag {
349 #[must_use]
355 pub fn new(value: impl Into<String>) -> Self {
356 let value = value.into();
357 let value = value.strip_prefix('!').unwrap_or(&value);
358 assert!(!value.is_empty(), "YAML tags cannot be empty");
359 Self {
360 string: value.to_owned(),
361 }
362 }
363
364 pub(crate) fn as_suffix(&self) -> &str {
365 &self.string
366 }
367}
368
369impl fmt::Display for Tag {
370 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
371 write!(formatter, "!{}", self.string)
372 }
373}
374
375impl fmt::Debug for Tag {
376 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
377 formatter
378 .debug_tuple("Tag")
379 .field(&self.to_string())
380 .finish()
381 }
382}
383
384impl PartialEq<str> for Tag {
385 fn eq(&self, other: &str) -> bool {
386 self.string == other.strip_prefix('!').unwrap_or(other)
387 }
388}
389
390impl PartialEq<&str> for Tag {
391 fn eq(&self, other: &&str) -> bool {
392 self == *other
393 }
394}
395
396impl PartialEq<String> for Tag {
397 fn eq(&self, other: &String) -> bool {
398 self == other.as_str()
399 }
400}
401
402impl Serialize for Tag {
403 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
404 where
405 S: serde::Serializer,
406 {
407 serializer.serialize_str(&self.to_string())
408 }
409}
410
411impl<'de> Deserialize<'de> for Tag {
412 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
413 where
414 D: Deserializer<'de>,
415 {
416 String::deserialize(deserializer).map(Self::new)
417 }
418}
419
420#[derive(Clone, Debug, PartialEq, PartialOrd, Hash)]
422pub struct TaggedValue {
423 pub tag: Tag,
425 pub value: Value,
427}
428
429impl Eq for TaggedValue {}
430
431impl Serialize for TaggedValue {
432 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
433 where
434 S: serde::Serializer,
435 {
436 Value::Tagged(Box::new(self.clone())).serialize(serializer)
437 }
438}
439
440impl<'de> Deserialize<'de> for TaggedValue {
441 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
442 where
443 D: Deserializer<'de>,
444 {
445 match Value::deserialize(deserializer)? {
446 Value::Tagged(value) => Ok(*value),
447 _ => Err(serde::de::Error::custom("expected a tagged YAML value")),
448 }
449 }
450}
451
452impl From<Mapping> for Value {
453 fn from(value: Mapping) -> Self {
454 Self::Mapping(value)
455 }
456}
457
458impl From<String> for Value {
459 fn from(value: String) -> Self {
460 Self::String(value)
461 }
462}
463
464impl From<&str> for Value {
465 fn from(value: &str) -> Self {
466 Self::String(value.to_owned())
467 }
468}
469
470impl From<Cow<'_, str>> for Value {
471 fn from(value: Cow<'_, str>) -> Self {
472 Self::String(value.into_owned())
473 }
474}
475
476impl From<bool> for Value {
477 fn from(value: bool) -> Self {
478 Self::Bool(value)
479 }
480}
481
482macro_rules! number_conversions {
483 ($($ty:ty),+ $(,)?) => {
484 $(
485 impl From<$ty> for Value {
486 fn from(value: $ty) -> Self {
487 Self::Number(Number::from(value))
488 }
489 }
490
491 impl PartialEq<$ty> for Value {
492 fn eq(&self, other: &$ty) -> bool {
493 self == &Self::from(*other)
494 }
495 }
496
497 impl PartialEq<Value> for $ty {
498 fn eq(&self, other: &Value) -> bool {
499 &Value::from(*self) == other
500 }
501 }
502 )+
503 };
504}
505
506number_conversions!(
507 i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64,
508);
509
510impl<T> From<Vec<T>> for Value
511where
512 T: Into<Value>,
513{
514 fn from(values: Vec<T>) -> Self {
515 Self::Sequence(values.into_iter().map(Into::into).collect())
516 }
517}
518
519impl<T> From<&[T]> for Value
520where
521 T: Clone + Into<Value>,
522{
523 fn from(values: &[T]) -> Self {
524 Self::Sequence(values.iter().cloned().map(Into::into).collect())
525 }
526}
527
528impl<T> FromIterator<T> for Value
529where
530 T: Into<Value>,
531{
532 fn from_iter<I>(iter: I) -> Self
533 where
534 I: IntoIterator<Item = T>,
535 {
536 Self::Sequence(iter.into_iter().map(Into::into).collect())
537 }
538}
539
540impl PartialEq<str> for Value {
541 fn eq(&self, other: &str) -> bool {
542 self.as_str().is_some_and(|value| value == other)
543 }
544}
545
546impl PartialEq<&str> for Value {
547 fn eq(&self, other: &&str) -> bool {
548 self == *other
549 }
550}
551
552impl PartialEq<String> for Value {
553 fn eq(&self, other: &String) -> bool {
554 self == other.as_str()
555 }
556}
557
558impl PartialEq<bool> for Value {
559 fn eq(&self, other: &bool) -> bool {
560 self.as_bool().is_some_and(|value| value == *other)
561 }
562}
563
564impl PartialEq<Value> for bool {
565 fn eq(&self, other: &Value) -> bool {
566 other == self
567 }
568}
569
570impl PartialEq<Value> for str {
571 fn eq(&self, other: &Value) -> bool {
572 other == self
573 }
574}
575
576impl PartialEq<Value> for String {
577 fn eq(&self, other: &Value) -> bool {
578 other == self
579 }
580}