Skip to main content

yaml_rt_serde/
de.rs

1use std::{borrow::Cow, cell::Cell, io::Read, rc::Rc, str};
2
3use serde::Deserializer as _;
4use serde::de::{
5    self, DeserializeOwned, DeserializeSeed, EnumAccess, MapAccess, SeqAccess, VariantAccess,
6    Visitor,
7};
8use yaml_rt_core::{
9    NodeId, NonFiniteFloat, ResolvedScalar, SemanticKind, Span, YamlDoc, YamlScalarStyle,
10    resolve_scalar,
11};
12
13use crate::{Error, Result};
14
15const MAX_DEPTH: u8 = 128;
16
17struct Input<'de> {
18    doc: Option<YamlDoc>,
19    borrowed: Option<&'de str>,
20    error: Option<Error>,
21    semantic_len: usize,
22}
23
24impl<'de> Input<'de> {
25    fn parsed(text: String, borrowed: Option<&'de str>) -> Self {
26        match YamlDoc::parse_owned(text) {
27            Ok(doc) => {
28                let semantic_len = doc.events().count().max(1);
29                Self {
30                    doc: Some(doc),
31                    borrowed,
32                    error: None,
33                    semantic_len,
34                }
35            }
36            Err(error) => Self {
37                doc: None,
38                borrowed,
39                error: Some(error.into()),
40                semantic_len: 1,
41            },
42        }
43    }
44
45    fn failed(error: Error) -> Self {
46        Self {
47            doc: None,
48            borrowed: None,
49            error: Some(error),
50            semantic_len: 1,
51        }
52    }
53}
54
55/// A Serde deserializer over one YAML stream.
56pub struct Deserializer<'de> {
57    input: Rc<Input<'de>>,
58    selected: Option<usize>,
59    next_index: usize,
60    yielded_error: bool,
61}
62
63impl<'de> Deserializer<'de> {
64    /// Creates a deserializer borrowing a UTF-8 YAML string.
65    #[must_use]
66    #[expect(
67        clippy::should_implement_trait,
68        reason = "FromStr cannot retain the borrowed input lifetime or this constructor's deferred errors"
69    )]
70    pub fn from_str(input: &'de str) -> Self {
71        Self::new(Input::parsed(input.to_owned(), Some(input)))
72    }
73
74    /// Creates a deserializer borrowing a UTF-8 YAML byte slice.
75    #[must_use]
76    pub fn from_slice(input: &'de [u8]) -> Self {
77        match str::from_utf8(input) {
78            Ok(input) => Self::from_str(input),
79            Err(error) => Self::new(Input::failed(Error::message(error.to_string()))),
80        }
81    }
82
83    fn new(input: Input<'de>) -> Self {
84        Self {
85            input: Rc::new(input),
86            selected: None,
87            next_index: 0,
88            yielded_error: false,
89        }
90    }
91
92    fn node_deserializer(&self) -> Result<NodeDeserializer<'_, 'de>> {
93        if let Some(error) = &self.input.error {
94            return Err(error.clone());
95        }
96        let doc = self
97            .input
98            .doc
99            .as_ref()
100            .expect("parsed input has a document");
101        let index = if let Some(index) = self.selected {
102            index
103        } else {
104            match doc.document_count() {
105                0 => return Err(Error::message("EOF while parsing a value")),
106                1 => 0,
107                _ => {
108                    return Err(Error::message(
109                        "deserializing from YAML containing more than one document is not supported",
110                    ));
111                }
112            }
113        };
114        let node = doc.document_root(index).map_err(Error::from)?;
115        Ok(NodeDeserializer {
116            input: &self.input,
117            node,
118            path: ".".to_owned(),
119            depth: MAX_DEPTH,
120            alias_jumps: Rc::new(Cell::new(0)),
121            ignore_tag: false,
122        })
123    }
124}
125
126impl Deserializer<'static> {
127    /// Creates a deserializer by reading an owned UTF-8 YAML stream.
128    #[must_use]
129    pub fn from_reader<R>(mut reader: R) -> Self
130    where
131        R: Read,
132    {
133        let mut input = String::new();
134        match reader.read_to_string(&mut input) {
135            Ok(_) => Self::new(Input::parsed(input, None)),
136            Err(error) => Self::new(Input::failed(Error::io(error))),
137        }
138    }
139}
140
141impl Iterator for Deserializer<'_> {
142    type Item = Self;
143
144    fn next(&mut self) -> Option<Self::Item> {
145        if self.input.error.is_some() {
146            if self.yielded_error {
147                return None;
148            }
149            self.yielded_error = true;
150            return Some(Self {
151                input: Rc::clone(&self.input),
152                selected: Some(0),
153                next_index: 0,
154                yielded_error: true,
155            });
156        }
157        let count = self.input.doc.as_ref()?.document_count();
158        if self.next_index >= count {
159            return None;
160        }
161        let selected = self.next_index;
162        self.next_index += 1;
163        Some(Self {
164            input: Rc::clone(&self.input),
165            selected: Some(selected),
166            next_index: 0,
167            yielded_error: false,
168        })
169    }
170}
171
172/// Deserializes exactly one YAML document from a string.
173///
174/// # Errors
175///
176/// Returns an error when the YAML is invalid, does not contain exactly one
177/// document, or cannot be deserialized as `T`.
178pub fn from_str<'de, T>(input: &'de str) -> Result<T>
179where
180    T: serde::Deserialize<'de>,
181{
182    T::deserialize(Deserializer::from_str(input))
183}
184
185/// Deserializes exactly one YAML document from a byte slice.
186///
187/// # Errors
188///
189/// Returns an error when the bytes are not UTF-8, the YAML is invalid, or the
190/// document cannot be deserialized as `T`.
191pub fn from_slice<'de, T>(input: &'de [u8]) -> Result<T>
192where
193    T: serde::Deserialize<'de>,
194{
195    T::deserialize(Deserializer::from_slice(input))
196}
197
198/// Deserializes exactly one owned YAML document from a reader.
199///
200/// # Errors
201///
202/// Returns an error when reading fails, the YAML is invalid, or the document
203/// cannot be deserialized as `T`.
204pub fn from_reader<R, T>(reader: R) -> Result<T>
205where
206    R: Read,
207    T: DeserializeOwned,
208{
209    T::deserialize(Deserializer::from_reader(reader))
210}
211
212macro_rules! delegate_deserializer {
213    ($($method:ident $(($($arg:ident : $ty:ty),*))?;)+) => {
214        $(
215            fn $method<V>(self, $($($arg: $ty,)*)? visitor: V) -> Result<V::Value>
216            where
217                V: Visitor<'de>,
218            {
219                self.node_deserializer()?.$method($($($arg,)*)? visitor)
220            }
221        )+
222    };
223}
224
225impl<'de> de::Deserializer<'de> for Deserializer<'de> {
226    type Error = Error;
227
228    delegate_deserializer! {
229        deserialize_any;
230        deserialize_bool;
231        deserialize_i8;
232        deserialize_i16;
233        deserialize_i32;
234        deserialize_i64;
235        deserialize_i128;
236        deserialize_u8;
237        deserialize_u16;
238        deserialize_u32;
239        deserialize_u64;
240        deserialize_u128;
241        deserialize_f32;
242        deserialize_f64;
243        deserialize_char;
244        deserialize_str;
245        deserialize_string;
246        deserialize_bytes;
247        deserialize_byte_buf;
248        deserialize_option;
249        deserialize_unit;
250        deserialize_unit_struct(name: &'static str);
251        deserialize_newtype_struct(name: &'static str);
252        deserialize_seq;
253        deserialize_tuple(len: usize);
254        deserialize_tuple_struct(name: &'static str, len: usize);
255        deserialize_map;
256        deserialize_struct(name: &'static str, fields: &'static [&'static str]);
257        deserialize_enum(name: &'static str, variants: &'static [&'static str]);
258        deserialize_identifier;
259        deserialize_ignored_any;
260    }
261
262    fn is_human_readable(&self) -> bool {
263        true
264    }
265}
266
267#[derive(Clone)]
268struct NodeDeserializer<'input, 'de> {
269    input: &'input Input<'de>,
270    node: Option<NodeId>,
271    path: String,
272    depth: u8,
273    alias_jumps: Rc<Cell<usize>>,
274    ignore_tag: bool,
275}
276
277impl<'input, 'de> NodeDeserializer<'input, 'de> {
278    fn doc(&self) -> &'input YamlDoc {
279        self.input.doc.as_ref().expect("node input is parsed")
280    }
281
282    fn span(&self) -> Span {
283        self.node
284            .and_then(|node| self.doc().node(node).map(yaml_rt_core::Node::span))
285            .unwrap_or_else(|| Span::empty(0))
286    }
287
288    fn annotate<T>(&self, result: Result<T>) -> Result<T> {
289        result.map_err(|error| error.at(self.doc(), self.span()).with_path(&self.path))
290    }
291
292    fn descend(&self, node: Option<NodeId>, path: String) -> Result<Self> {
293        let depth = self
294            .depth
295            .checked_sub(1)
296            .ok_or_else(|| Error::message("recursion limit exceeded"));
297        let depth = self.annotate(depth)?;
298        Ok(Self {
299            input: self.input,
300            node,
301            path,
302            depth,
303            alias_jumps: Rc::clone(&self.alias_jumps),
304            ignore_tag: false,
305        })
306    }
307
308    fn resolved(mut self) -> Result<Self> {
309        let mut seen = Vec::new();
310        while let Some(node) = self.node {
311            if !matches!(self.doc().semantic_kind(node), Some(SemanticKind::Alias)) {
312                break;
313            }
314            if seen.contains(&node) {
315                return self.annotate(Err(Error::message("recursive alias")));
316            }
317            seen.push(node);
318            let jumps = self.alias_jumps.get().saturating_add(1);
319            self.alias_jumps.set(jumps);
320            if jumps > self.input.semantic_len.saturating_mul(100) {
321                return self.annotate(Err(Error::message("alias repetition limit exceeded")));
322            }
323            let target = self.doc().resolve_alias(node).ok_or_else(|| {
324                Error::message(format!(
325                    "unknown anchor `{}`",
326                    self.doc().alias_name(node).unwrap_or_default()
327                ))
328            });
329            self.node = Some(self.annotate(target)?);
330        }
331        Ok(self)
332    }
333
334    fn child(&self, node: Option<NodeId>, path: String) -> Result<Self> {
335        self.descend(node, path)
336    }
337
338    fn scalar(&self) -> Result<(NodeId, Cow<'input, str>)> {
339        let node = self
340            .node
341            .ok_or_else(|| Error::message("expected a scalar, found null"));
342        let node = self.annotate(node)?;
343        if !matches!(
344            self.doc().semantic_kind(node),
345            Some(SemanticKind::Scalar { .. })
346        ) {
347            return self.annotate(Err(Error::message("expected a scalar value")));
348        }
349        let value = self
350            .doc()
351            .scalar_value(node)
352            .map(|value| (node, value))
353            .map_err(Error::from);
354        self.annotate(value)
355    }
356
357    fn custom_tag(&self) -> Option<String> {
358        if self.ignore_tag {
359            return None;
360        }
361        let raw = self.node.and_then(|node| self.doc().raw_tag(node))?;
362        if raw.starts_with("!!") || raw.starts_with("!<") || !raw.starts_with('!') {
363            return None;
364        }
365        let tag = raw.strip_prefix('!')?;
366        (!tag.is_empty()).then(|| tag.to_owned())
367    }
368
369    fn scalar_kind(&self) -> Result<ScalarKind> {
370        let Some(node) = self.node else {
371            return Ok(ScalarKind::Null);
372        };
373        let Some(SemanticKind::Scalar { style }) = self.doc().semantic_kind(node) else {
374            return Err(Error::message("expected a scalar value"));
375        };
376        let value = self.doc().scalar_value(node).map_err(Error::from)?;
377        let tag = self
378            .doc()
379            .resolved_tag(node)
380            .map_err(Error::from)?
381            .map(Cow::into_owned);
382        let resolved = resolve_scalar(&value, style, tag.as_deref())
383            .map_err(|error| Error::message(error.to_string()))?;
384        self.annotate(scalar_kind_from_resolved(resolved))
385    }
386
387    fn borrowed_scalar(&self, node: NodeId) -> Option<&'de str> {
388        let source = self.input.borrowed?;
389        let span = self.doc().borrowable_scalar_span(node).ok()??;
390        source.get(span.start as usize..span.end as usize)
391    }
392
393    fn is_empty_plain(&self) -> bool {
394        let Some(node) = self.node else {
395            return true;
396        };
397        matches!(
398            self.doc().semantic_kind(node),
399            Some(SemanticKind::Scalar {
400                style: YamlScalarStyle::Plain
401            })
402        ) && self
403            .doc()
404            .scalar_value(node)
405            .is_ok_and(|value| value.is_empty())
406    }
407}
408
409#[derive(Clone, Copy)]
410enum ScalarKind {
411    Null,
412    Bool(bool),
413    Signed(i128),
414    Unsigned(u128),
415    Float(f64),
416    String,
417}
418
419fn scalar_kind_from_resolved(value: ResolvedScalar) -> Result<ScalarKind> {
420    match value {
421        ResolvedScalar::Null => Ok(ScalarKind::Null),
422        ResolvedScalar::Bool(value) => Ok(ScalarKind::Bool(value)),
423        ResolvedScalar::Number(number) if number.has_integer_syntax() => {
424            if let Some(value) = number.as_i128()
425                && value < 0
426            {
427                Ok(ScalarKind::Signed(value))
428            } else if let Some(value) = number.as_u128() {
429                Ok(ScalarKind::Unsigned(value))
430            } else if let Some(value) = number.as_i128() {
431                Ok(ScalarKind::Signed(value))
432            } else {
433                Err(Error::message("integer is outside the supported range"))
434            }
435        }
436        ResolvedScalar::Number(number) => number
437            .as_f64()
438            .map(ScalarKind::Float)
439            .ok_or_else(|| Error::message("float is outside the supported range")),
440        ResolvedScalar::NonFinite(NonFiniteFloat::PositiveInfinity) => {
441            Ok(ScalarKind::Float(f64::INFINITY))
442        }
443        ResolvedScalar::NonFinite(NonFiniteFloat::NegativeInfinity) => {
444            Ok(ScalarKind::Float(f64::NEG_INFINITY))
445        }
446        ResolvedScalar::NonFinite(NonFiniteFloat::NaN) => Ok(ScalarKind::Float(f64::NAN)),
447        ResolvedScalar::String => Ok(ScalarKind::String),
448    }
449}
450
451impl<'de> de::Deserializer<'de> for NodeDeserializer<'_, 'de> {
452    type Error = Error;
453
454    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
455    where
456        V: Visitor<'de>,
457    {
458        let this = self.resolved()?;
459        if let Some(variant) = this.custom_tag() {
460            return visitor.visit_enum(YamlEnumAccess { de: this, variant });
461        }
462        let result = match this.node.and_then(|node| this.doc().semantic_kind(node)) {
463            None => visitor.visit_unit(),
464            Some(SemanticKind::Scalar { .. }) => match this.scalar_kind()? {
465                ScalarKind::Null => visitor.visit_unit(),
466                ScalarKind::Bool(value) => visitor.visit_bool(value),
467                ScalarKind::Signed(value) => visitor.visit_i128(value),
468                ScalarKind::Unsigned(value) => visitor.visit_u128(value),
469                ScalarKind::Float(value) => visitor.visit_f64(value),
470                ScalarKind::String => this.clone().deserialize_str(visitor),
471            },
472            Some(SemanticKind::Sequence { .. }) => this.clone().deserialize_seq(visitor),
473            Some(SemanticKind::Mapping { .. }) => this.clone().deserialize_map(visitor),
474            Some(SemanticKind::Alias) => unreachable!("aliases were resolved"),
475            Some(SemanticKind::Document) => Err(Error::message("unexpected document node")),
476        };
477        this.annotate(result)
478    }
479
480    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
481    where
482        V: Visitor<'de>,
483    {
484        let this = self.resolved()?;
485        let result = match this.scalar_kind()? {
486            ScalarKind::Bool(value) => visitor.visit_bool(value),
487            _ => Err(Error::message("expected a boolean")),
488        };
489        this.annotate(result)
490    }
491
492    fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
493    where
494        V: Visitor<'de>,
495    {
496        deserialize_signed(self, visitor, |v| i8::try_from(v).ok(), Visitor::visit_i8)
497    }
498    fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
499    where
500        V: Visitor<'de>,
501    {
502        deserialize_signed(self, visitor, |v| i16::try_from(v).ok(), Visitor::visit_i16)
503    }
504    fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
505    where
506        V: Visitor<'de>,
507    {
508        deserialize_signed(self, visitor, |v| i32::try_from(v).ok(), Visitor::visit_i32)
509    }
510    fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
511    where
512        V: Visitor<'de>,
513    {
514        deserialize_signed(self, visitor, |v| i64::try_from(v).ok(), Visitor::visit_i64)
515    }
516    fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value>
517    where
518        V: Visitor<'de>,
519    {
520        deserialize_signed(self, visitor, Some, Visitor::visit_i128)
521    }
522    fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
523    where
524        V: Visitor<'de>,
525    {
526        deserialize_unsigned(self, visitor, |v| u8::try_from(v).ok(), Visitor::visit_u8)
527    }
528    fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
529    where
530        V: Visitor<'de>,
531    {
532        deserialize_unsigned(self, visitor, |v| u16::try_from(v).ok(), Visitor::visit_u16)
533    }
534    fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
535    where
536        V: Visitor<'de>,
537    {
538        deserialize_unsigned(self, visitor, |v| u32::try_from(v).ok(), Visitor::visit_u32)
539    }
540    fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
541    where
542        V: Visitor<'de>,
543    {
544        deserialize_unsigned(self, visitor, |v| u64::try_from(v).ok(), Visitor::visit_u64)
545    }
546    fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value>
547    where
548        V: Visitor<'de>,
549    {
550        deserialize_unsigned(self, visitor, Some, Visitor::visit_u128)
551    }
552
553    fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
554    where
555        V: Visitor<'de>,
556    {
557        deserialize_float(self, visitor, |visitor, value| {
558            let value = checked_f64_to_f32(value)
559                .ok_or_else(|| Error::message("expected an f32 in range"))?;
560            visitor.visit_f32(value)
561        })
562    }
563
564    fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
565    where
566        V: Visitor<'de>,
567    {
568        deserialize_float(self, visitor, Visitor::visit_f64)
569    }
570
571    fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
572    where
573        V: Visitor<'de>,
574    {
575        let this = self.resolved()?;
576        let (_, value) = this.scalar()?;
577        let mut chars = value.chars();
578        let value = chars
579            .next()
580            .filter(|_| chars.next().is_none())
581            .ok_or_else(|| Error::message("expected a single character"));
582        this.annotate(value.and_then(|value| visitor.visit_char(value)))
583    }
584
585    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
586    where
587        V: Visitor<'de>,
588    {
589        let this = self.resolved()?;
590        let (node, value) = this.scalar()?;
591        let result = if let Some(value) = this.borrowed_scalar(node) {
592            visitor.visit_borrowed_str(value)
593        } else {
594            match value {
595                Cow::Borrowed(value) => visitor.visit_str(value),
596                Cow::Owned(value) => visitor.visit_string(value),
597            }
598        };
599        this.annotate(result)
600    }
601
602    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
603    where
604        V: Visitor<'de>,
605    {
606        let this = self.resolved()?;
607        let (_, value) = this.scalar()?;
608        this.annotate(visitor.visit_string(value.into_owned()))
609    }
610
611    fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::Value>
612    where
613        V: Visitor<'de>,
614    {
615        Err(Error::message(
616            "serialization and deserialization of bytes in YAML is not implemented",
617        ))
618    }
619
620    fn deserialize_byte_buf<V>(self, _visitor: V) -> Result<V::Value>
621    where
622        V: Visitor<'de>,
623    {
624        Err(Error::message(
625            "serialization and deserialization of bytes in YAML is not implemented",
626        ))
627    }
628
629    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
630    where
631        V: Visitor<'de>,
632    {
633        let this = self.resolved()?;
634        if matches!(this.scalar_kind(), Ok(ScalarKind::Null)) {
635            this.annotate(visitor.visit_none())
636        } else {
637            visitor.visit_some(this)
638        }
639    }
640
641    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
642    where
643        V: Visitor<'de>,
644    {
645        let this = self.resolved()?;
646        let result = if matches!(this.scalar_kind(), Ok(ScalarKind::Null)) {
647            visitor.visit_unit()
648        } else {
649            Err(Error::message("expected null"))
650        };
651        this.annotate(result)
652    }
653
654    fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
655    where
656        V: Visitor<'de>,
657    {
658        self.deserialize_unit(visitor)
659    }
660
661    fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
662    where
663        V: Visitor<'de>,
664    {
665        visitor.visit_newtype_struct(self)
666    }
667
668    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
669    where
670        V: Visitor<'de>,
671    {
672        let this = self.resolved()?;
673        if this.is_empty_plain() {
674            return this.annotate(visitor.visit_seq(EmptyAccess));
675        }
676        let node = this
677            .node
678            .ok_or_else(|| Error::message("expected a sequence"))?;
679        if !matches!(
680            this.doc().semantic_kind(node),
681            Some(SemanticKind::Sequence { .. })
682        ) {
683            return this.annotate(Err(Error::message("expected a sequence")));
684        }
685        let items = this.doc().sequence_items(node).collect::<Vec<_>>();
686        let context = this.clone();
687        context.annotate(visitor.visit_seq(YamlSeqAccess {
688            de: this,
689            items,
690            index: 0,
691        }))
692    }
693
694    fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value>
695    where
696        V: Visitor<'de>,
697    {
698        self.deserialize_seq(visitor)
699    }
700
701    fn deserialize_tuple_struct<V>(
702        self,
703        _name: &'static str,
704        _len: usize,
705        visitor: V,
706    ) -> Result<V::Value>
707    where
708        V: Visitor<'de>,
709    {
710        self.deserialize_seq(visitor)
711    }
712
713    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
714    where
715        V: Visitor<'de>,
716    {
717        let this = self.resolved()?;
718        if this.is_empty_plain() {
719            return this.annotate(visitor.visit_map(EmptyAccess));
720        }
721        let node = this
722            .node
723            .ok_or_else(|| Error::message("expected a mapping"))?;
724        if !matches!(
725            this.doc().semantic_kind(node),
726            Some(SemanticKind::Mapping { .. })
727        ) {
728            return this.annotate(Err(Error::message("expected a mapping")));
729        }
730        let entries = this.doc().mapping_entries(node).collect::<Vec<_>>();
731        let context = this.clone();
732        context.annotate(visitor.visit_map(YamlMapAccess {
733            de: this,
734            entries,
735            index: 0,
736            pending: None,
737        }))
738    }
739
740    fn deserialize_struct<V>(
741        self,
742        _name: &'static str,
743        _fields: &'static [&'static str],
744        visitor: V,
745    ) -> Result<V::Value>
746    where
747        V: Visitor<'de>,
748    {
749        self.deserialize_map(visitor)
750    }
751
752    fn deserialize_enum<V>(
753        self,
754        _name: &'static str,
755        _variants: &'static [&'static str],
756        visitor: V,
757    ) -> Result<V::Value>
758    where
759        V: Visitor<'de>,
760    {
761        let this = self.resolved()?;
762        let variant = if let Some(variant) = this.custom_tag() {
763            variant
764        } else {
765            let (_, value) = this.scalar()?;
766            value.into_owned()
767        };
768        let context = this.clone();
769        context.annotate(visitor.visit_enum(YamlEnumAccess { de: this, variant }))
770    }
771
772    fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
773    where
774        V: Visitor<'de>,
775    {
776        self.deserialize_str(visitor)
777    }
778
779    fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
780    where
781        V: Visitor<'de>,
782    {
783        visitor.visit_unit()
784    }
785
786    fn is_human_readable(&self) -> bool {
787        true
788    }
789}
790
791fn signed_value(kind: ScalarKind) -> Option<i128> {
792    match kind {
793        ScalarKind::Signed(value) => Some(value),
794        ScalarKind::Unsigned(value) => i128::try_from(value).ok(),
795        _ => None,
796    }
797}
798
799fn unsigned_value(kind: ScalarKind) -> Option<u128> {
800    match kind {
801        ScalarKind::Unsigned(value) => Some(value),
802        ScalarKind::Signed(value) => u128::try_from(value).ok(),
803        _ => None,
804    }
805}
806
807fn deserialize_signed<'de, V, T>(
808    de: NodeDeserializer<'_, 'de>,
809    visitor: V,
810    convert: impl FnOnce(i128) -> Option<T>,
811    visit: impl FnOnce(V, T) -> Result<V::Value>,
812) -> Result<V::Value>
813where
814    V: Visitor<'de>,
815{
816    let de = de.resolved()?;
817    let value = signed_value(de.scalar_kind()?)
818        .and_then(convert)
819        .ok_or_else(|| Error::message("expected an integer in range"));
820    de.annotate(value.and_then(|value| visit(visitor, value)))
821}
822
823fn deserialize_unsigned<'de, V, T>(
824    de: NodeDeserializer<'_, 'de>,
825    visitor: V,
826    convert: impl FnOnce(u128) -> Option<T>,
827    visit: impl FnOnce(V, T) -> Result<V::Value>,
828) -> Result<V::Value>
829where
830    V: Visitor<'de>,
831{
832    let de = de.resolved()?;
833    let value = unsigned_value(de.scalar_kind()?)
834        .and_then(convert)
835        .ok_or_else(|| Error::message("expected an unsigned integer in range"));
836    de.annotate(value.and_then(|value| visit(visitor, value)))
837}
838
839fn deserialize_float<'de, V>(
840    de: NodeDeserializer<'_, 'de>,
841    visitor: V,
842    visit: impl FnOnce(V, f64) -> Result<V::Value>,
843) -> Result<V::Value>
844where
845    V: Visitor<'de>,
846{
847    let de = de.resolved()?;
848    let value = match de.scalar_kind()? {
849        ScalarKind::Float(value) => Some(value),
850        ScalarKind::Signed(value) => Some(i128_to_f64(value)),
851        ScalarKind::Unsigned(value) => Some(u128_to_f64(value)),
852        _ => None,
853    }
854    .ok_or_else(|| Error::message("expected a number"));
855    de.annotate(value.and_then(|value| visit(visitor, value)))
856}
857
858fn checked_f64_to_f32(value: f64) -> Option<f32> {
859    // Rust defines this conversion as rounding to the nearest representable
860    // `f32`; reject only finite overflow instead of silently producing infinity.
861    #[expect(
862        clippy::cast_possible_truncation,
863        reason = "f32 deserialization applies Rust narrowing and then rejects finite overflow"
864    )]
865    let converted = value as f32;
866    (!value.is_finite() || converted.is_finite()).then_some(converted)
867}
868
869fn i128_to_f64(value: i128) -> f64 {
870    // Deserializing an integer into an explicitly requested floating-point type
871    // follows Rust's rounding semantics when the integer exceeds 53 bits.
872    #[expect(
873        clippy::cast_precision_loss,
874        reason = "Serde floating-point requests intentionally use Rust integer rounding semantics"
875    )]
876    let converted = value as f64;
877    converted
878}
879
880fn u128_to_f64(value: u128) -> f64 {
881    // See `i128_to_f64`; all `u128` values remain finite as `f64`.
882    #[expect(
883        clippy::cast_precision_loss,
884        reason = "Serde floating-point requests intentionally use Rust integer rounding semantics"
885    )]
886    let converted = value as f64;
887    converted
888}
889
890struct EmptyAccess;
891
892impl<'de> SeqAccess<'de> for EmptyAccess {
893    type Error = Error;
894    fn next_element_seed<T>(&mut self, _seed: T) -> Result<Option<T::Value>>
895    where
896        T: DeserializeSeed<'de>,
897    {
898        Ok(None)
899    }
900}
901
902impl<'de> MapAccess<'de> for EmptyAccess {
903    type Error = Error;
904    fn next_key_seed<K>(&mut self, _seed: K) -> Result<Option<K::Value>>
905    where
906        K: DeserializeSeed<'de>,
907    {
908        Ok(None)
909    }
910    fn next_value_seed<V>(&mut self, _seed: V) -> Result<V::Value>
911    where
912        V: DeserializeSeed<'de>,
913    {
914        Err(Error::message("value requested without a key"))
915    }
916}
917
918struct YamlSeqAccess<'input, 'de> {
919    de: NodeDeserializer<'input, 'de>,
920    items: Vec<NodeId>,
921    index: usize,
922}
923
924impl<'de> SeqAccess<'de> for YamlSeqAccess<'_, 'de> {
925    type Error = Error;
926    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
927    where
928        T: DeserializeSeed<'de>,
929    {
930        let Some(node) = self.items.get(self.index).copied() else {
931            return Ok(None);
932        };
933        let index = self.index;
934        self.index += 1;
935        let child = self
936            .de
937            .child(Some(node), format!("{}[{index}]", self.de.path))?;
938        seed.deserialize(child).map(Some)
939    }
940    fn size_hint(&self) -> Option<usize> {
941        Some(self.items.len().saturating_sub(self.index))
942    }
943}
944
945struct YamlMapAccess<'input, 'de> {
946    de: NodeDeserializer<'input, 'de>,
947    entries: Vec<(NodeId, NodeId)>,
948    index: usize,
949    pending: Option<(NodeId, String)>,
950}
951
952impl<'de> MapAccess<'de> for YamlMapAccess<'_, 'de> {
953    type Error = Error;
954    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
955    where
956        K: DeserializeSeed<'de>,
957    {
958        let Some((key, value)) = self.entries.get(self.index).copied() else {
959            return Ok(None);
960        };
961        self.index += 1;
962        let key_name = self
963            .de
964            .doc()
965            .scalar_value(key)
966            .ok()
967            .map_or_else(|| "?".to_owned(), Cow::into_owned);
968        let path = if key_name
969            .chars()
970            .all(|c| c.is_alphanumeric() || c == '_' || c == '-')
971        {
972            format!("{}.{}", self.de.path.trim_end_matches('.'), key_name)
973        } else {
974            format!("{}[{:?}]", self.de.path, key_name)
975        };
976        self.pending = Some((value, path));
977        let child = self
978            .de
979            .child(Some(key), format!("{}.<key>", self.de.path))?;
980        seed.deserialize(child).map(Some)
981    }
982    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
983    where
984        V: DeserializeSeed<'de>,
985    {
986        let (node, path) = self
987            .pending
988            .take()
989            .ok_or_else(|| Error::message("value requested without a key"))?;
990        seed.deserialize(self.de.child(Some(node), path)?)
991    }
992    fn size_hint(&self) -> Option<usize> {
993        Some(self.entries.len().saturating_sub(self.index))
994    }
995}
996
997struct YamlEnumAccess<'input, 'de> {
998    de: NodeDeserializer<'input, 'de>,
999    variant: String,
1000}
1001
1002impl<'input, 'de> EnumAccess<'de> for YamlEnumAccess<'input, 'de> {
1003    type Error = Error;
1004    type Variant = YamlVariantAccess<'input, 'de>;
1005    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
1006    where
1007        V: DeserializeSeed<'de>,
1008    {
1009        let variant = seed.deserialize(serde::de::value::StrDeserializer::<Error>::new(
1010            self.variant.as_str(),
1011        ))?;
1012        Ok((variant, YamlVariantAccess { de: self.de }))
1013    }
1014}
1015
1016struct YamlVariantAccess<'input, 'de> {
1017    de: NodeDeserializer<'input, 'de>,
1018}
1019
1020impl<'de> VariantAccess<'de> for YamlVariantAccess<'_, 'de> {
1021    type Error = Error;
1022    fn unit_variant(self) -> Result<()> {
1023        Ok(())
1024    }
1025    fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
1026    where
1027        T: DeserializeSeed<'de>,
1028    {
1029        let mut de = self.de;
1030        de.ignore_tag = true;
1031        seed.deserialize(de)
1032    }
1033    fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value>
1034    where
1035        V: Visitor<'de>,
1036    {
1037        let mut de = self.de;
1038        de.ignore_tag = true;
1039        de.deserialize_tuple(len, visitor)
1040    }
1041    fn struct_variant<V>(self, fields: &'static [&'static str], visitor: V) -> Result<V::Value>
1042    where
1043        V: Visitor<'de>,
1044    {
1045        let mut de = self.de;
1046        de.ignore_tag = true;
1047        de.deserialize_struct("", fields, visitor)
1048    }
1049}