marked_yaml/
types.rs

1//! Various basic types for YAML handling
2//!
3
4use doc_comment::doc_comment;
5use hashlink::LinkedHashMap;
6use std::borrow::{Borrow, Cow};
7use std::fmt::{self, Display};
8use std::hash::{Hash, Hasher};
9use std::ops::{Deref, DerefMut};
10use yaml_rust::Yaml as YamlNode;
11
12/// A displayable marker for a YAML node
13///
14/// While `Marker` can be `Display`'d it doesn't understand what its source
15/// means.  This struct is the result of asking a Marker to render itself.
16///
17/// ```
18/// # use marked_yaml::*;
19/// let filenames = vec!["examples/everything.yaml"];
20/// let nodes: Vec<_> = filenames
21///     .iter()
22///     .enumerate()
23///     .map(|(i, name)| parse_yaml(i, std::fs::read_to_string(name).unwrap()).unwrap())
24///     .collect();
25/// for (n, node) in nodes.iter().enumerate() {
26///     let marker = node.span().start().unwrap();
27///     let rendered = format!("{}", marker.render(|i| filenames[i]));
28///     assert!(rendered.starts_with(filenames[n]));
29/// }
30/// ```
31pub struct RenderedMarker<D> {
32    source: D,
33    line: usize,
34    column: usize,
35}
36
37impl<D> Display for RenderedMarker<D>
38where
39    D: Display,
40{
41    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42        self.source.fmt(f)?;
43        write!(f, ":{}:{}", self.line, self.column)
44    }
45}
46
47/// A marker for a YAML node
48///
49/// This indicates where a node started or ended.
50///
51/// ```
52/// use marked_yaml::{parse_yaml, Marker};
53/// let node = parse_yaml(100, "{foo: bar}").unwrap();
54/// let map = node.as_mapping().unwrap();
55/// let bar = map.get("foo").unwrap();
56/// // the "bar" string started on line 1, column 7 of source ID 100.
57/// assert_eq!(bar.span().start(), Some(&Marker::new(100, 6, 1, 7)));
58/// ```
59#[derive(Copy, Clone, Debug, PartialEq, Eq)]
60pub struct Marker {
61    source: usize,
62    character: usize,
63    line: usize,
64    column: usize,
65}
66
67impl Marker {
68    /// Create a new Marker
69    ///
70    /// This will typically not be used because markers will come from
71    /// parsing YAML, however it is provided for completeness and in case
72    /// you need it for your own tests.
73    ///
74    /// ```
75    /// # use marked_yaml::Marker;
76    /// let marker = Marker::new(0, 3, 1, 2);
77    /// # assert_eq!(marker.source(), 0);
78    /// # assert_eq!(marker.character(), 3);
79    /// # assert_eq!(marker.line(), 1);
80    /// # assert_eq!(marker.column(), 2);
81    /// ```
82    pub fn new(source: usize, character: usize, line: usize, column: usize) -> Self {
83        Self {
84            source,
85            character,
86            line,
87            column,
88        }
89    }
90
91    /// The source index given for this marker.
92    ///
93    /// When parsing YAML, we record where nodes start (and often finish).
94    /// This is the source index provided when parsing the YAML.  Likely this
95    /// refers to a vector of PathBuf recording where input came from, but that
96    /// is entirely up to the user of this library crate.
97    ///
98    /// This is likely most useful to computers, not humans.
99    ///
100    /// ```
101    /// # use marked_yaml::Marker;
102    /// # let marker = Marker::new(0, 3, 1, 2);
103    /// assert_eq!(marker.source(), 0);
104    /// ```
105    pub fn source(&self) -> usize {
106        self.source
107    }
108
109    /// The character index at which this marker resides
110    ///
111    /// When parsing YAML, we record where nodes start (and often finish).
112    /// This is the character index into the source text of where this
113    /// marker resides.  Character indices start with zero since they're
114    /// meant for software rather than humans.
115    ///
116    /// ```
117    /// # use marked_yaml::Marker;
118    /// # let marker = Marker::new(0, 3, 1, 2);
119    /// assert_eq!(marker.character(), 3);
120    /// ```
121    pub fn character(&self) -> usize {
122        self.character
123    }
124
125    /// The line number on which this marker resides, 1-indexed
126    ///
127    /// When parsing YAML, we record where nodes start (and often finish).
128    /// This is the line number of where this marker resides.  Line numbers
129    /// start with 1 to make them more useful to humans.
130    ///
131    /// ```
132    /// # use marked_yaml::Marker;
133    /// # let marker = Marker::new(0, 3, 1, 2);
134    /// assert_eq!(marker.line(), 1);
135    /// ```
136    pub fn line(&self) -> usize {
137        self.line
138    }
139
140    /// The column number at which this marker resides, 1-indexed
141    ///
142    /// When parsing YAML, we record where nodes start (and often finish).
143    /// This is the column number of where this marker resides.  Column numbers
144    /// start with 1 to make them more useful to humans.
145    ///
146    /// ```
147    /// # use marked_yaml::Marker;
148    /// # let marker = Marker::new(0, 3, 1, 2);
149    /// assert_eq!(marker.column(), 2);
150    /// ```
151    pub fn column(&self) -> usize {
152        self.column
153    }
154
155    /// Render this marker
156    ///
157    /// Markers have a source identifier, typically as passed to `parse_yaml()`
158    /// but have no way in and of themselves to turn that into a useful name.
159    /// This function allows you to create a rendered marker which knows how
160    /// to show the source name.
161    ///
162    /// ```
163    /// # use marked_yaml::Marker;
164    /// # let marker = Marker::new(0, 3, 1, 2);
165    /// let rendered = marker.render(|_| "name");
166    /// assert_eq!(format!("{}", rendered), "name:1:2")
167    /// ```
168    pub fn render<D, F>(self, renderfn: F) -> RenderedMarker<D>
169    where
170        D: Display,
171        F: FnOnce(usize) -> D,
172    {
173        RenderedMarker {
174            source: renderfn(self.source),
175            line: self.line,
176            column: self.column,
177        }
178    }
179
180    /// Set the source index for this marker
181    ///
182    /// ```
183    /// # use marked_yaml::Marker;
184    /// # let mut marker = Marker::new(0, 0, 0, 0);
185    /// assert_ne!(marker.source(), 1);
186    /// marker.set_source(1);
187    /// assert_eq!(marker.source(), 1);
188    /// ```
189    pub fn set_source(&mut self, source: usize) {
190        self.source = source;
191    }
192
193    /// Set the character index for this marker
194    ///
195    ///
196    /// ```
197    /// # use marked_yaml::Marker;
198    /// # let mut marker = Marker::new(0, 0, 0, 0);
199    /// assert_ne!(marker.character(), 1);
200    /// marker.set_character(1);
201    /// assert_eq!(marker.character(), 1);
202    /// ```
203    pub fn set_character(&mut self, character: usize) {
204        self.character = character;
205    }
206
207    /// Set the line number for this marker
208    ///
209    /// ```
210    /// # use marked_yaml::Marker;
211    /// # let mut marker = Marker::new(0, 0, 0, 0);
212    /// assert_ne!(marker.line(), 1);
213    /// marker.set_line(1);
214    /// assert_eq!(marker.line(), 1);
215    /// ```
216    pub fn set_line(&mut self, line: usize) {
217        self.line = line;
218    }
219
220    /// Set the column number for this marker
221    ///
222    /// ```
223    /// # use marked_yaml::Marker;
224    /// # let mut marker = Marker::new(0, 0, 0, 0);
225    /// assert_ne!(marker.column(), 1);
226    /// marker.set_column(1);
227    /// assert_eq!(marker.column(), 1);
228    /// ```
229    pub fn set_column(&mut self, column: usize) {
230        self.column = column;
231    }
232}
233
234impl Display for Marker {
235    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
236        write!(f, "{}:{}", self.line, self.column)
237    }
238}
239
240/// The span for a YAML marked node
241///
242/// ```
243/// use marked_yaml::{parse_yaml, Marker, Span};
244/// let node = parse_yaml(100, "{foo: bar}").unwrap();
245/// let map = node.as_mapping().unwrap();
246/// assert_eq!(map.span(), &Span::new_with_marks(Marker::new(100, 0, 1, 1), Marker::new(100, 9, 1, 10)));
247/// ```
248#[derive(Copy, Clone, Debug, PartialEq, Eq)]
249pub struct Span {
250    start: Option<Marker>,
251    end: Option<Marker>,
252}
253
254impl Span {
255    /// Create a span with no marker information
256    ///
257    /// Sometimes we simply do not know where information came from (for example
258    /// if it was created by software) and in that case we can create a blank
259    /// span.
260    ///
261    /// ```
262    /// # use marked_yaml::Span;
263    /// let blank = Span::new_blank();
264    /// # assert_eq!(blank.start(), None);
265    /// # assert_eq!(blank.end(), None);
266    /// ```
267    pub fn new_blank() -> Self {
268        Self {
269            start: None,
270            end: None,
271        }
272    }
273
274    /// Create a span with only start information
275    ///
276    /// Sometimes when creating a span we know where it started but not where
277    /// it ends.  This might be during parsing, or for some other reason.
278    ///
279    /// ```
280    /// # use marked_yaml::{Marker, Span};
281    /// let span = Span::new_start(Marker::new(0, 1, 1, 2));
282    /// # assert_eq!(span.start().unwrap(), &Marker::new(0, 1, 1, 2));
283    /// # assert_eq!(span.end(), None);
284    /// ```
285    pub fn new_start(start: Marker) -> Self {
286        Self {
287            start: Some(start),
288            end: None,
289        }
290    }
291
292    /// Create a span with both start and end markers
293    ///
294    /// When we know both the start and end of a node, we can create a span
295    /// which has all that knowledge.
296    ///
297    /// ```
298    /// # use marked_yaml::{Marker,Span};
299    /// let span = Span::new_with_marks(Marker::new(0, 0, 1, 1), Marker::new(10, 1, 2, 1));
300    /// # assert_eq!(span.start().unwrap(), &Marker::new(0, 0, 1, 1));
301    /// # assert_eq!(span.end().unwrap(), &Marker::new(10, 1, 2, 1));
302    /// ```
303    pub fn new_with_marks(start: Marker, end: Marker) -> Self {
304        Self {
305            start: Some(start),
306            end: Some(end),
307        }
308    }
309
310    /// The start of the span
311    ///
312    /// ```
313    /// # use marked_yaml::{Marker, Span};
314    /// # let span = Span::new_with_marks(Marker::new(0, 0, 1, 1), Marker::new(10, 1, 2, 1));
315    /// assert_eq!(span.start(), Some(&Marker::new(0, 0, 1, 1)));
316    /// ```
317    pub fn start(&self) -> Option<&Marker> {
318        self.start.as_ref()
319    }
320
321    /// The end of the span
322    ///
323    /// ```
324    /// # use marked_yaml::{Marker, Span};
325    /// # let span = Span::new_with_marks(Marker::new(0, 0, 1, 1), Marker::new(10, 1, 2, 1));
326    /// assert_eq!(span.end(), Some(&Marker::new(10, 1, 2, 1)));
327    /// ```
328    pub fn end(&self) -> Option<&Marker> {
329        self.end.as_ref()
330    }
331
332    /// The start of the span, mutably
333    ///
334    /// ```
335    /// # use marked_yaml::{Marker, Span};
336    /// # let mut span = Span::new_with_marks(Marker::new(0, 0, 1, 1), Marker::new(10, 1, 2, 1));
337    /// span.start_mut().unwrap().set_line(5);
338    /// assert_eq!(span.start(), Some(&Marker::new(0, 0, 5, 1)));
339    /// ```
340    pub fn start_mut(&mut self) -> Option<&mut Marker> {
341        self.start.as_mut()
342    }
343
344    /// The end of the span, mutably
345    ///
346    /// ```
347    /// # use marked_yaml::{Marker, Span};
348    /// # let mut span = Span::new_with_marks(Marker::new(0, 0, 1, 1), Marker::new(10, 1, 2, 1));
349    /// span.end_mut().unwrap().set_line(5);
350    /// assert_eq!(span.end(), Some(&Marker::new(10, 1, 5, 1)));
351    /// ```
352    pub fn end_mut(&mut self) -> Option<&mut Marker> {
353        self.end.as_mut()
354    }
355
356    /// Replace the start of the span
357    ///
358    /// ```
359    /// # use marked_yaml::{Marker, Span};
360    /// # let mut span = Span::new_blank();
361    /// assert_eq!(span.start(), None);
362    /// span.set_start(Some(Marker::new(0, 1, 1, 2)));
363    /// assert_eq!(span.start(), Some(&Marker::new(0, 1, 1, 2)));
364    /// ```
365    pub fn set_start(&mut self, start: Option<Marker>) {
366        self.start = start;
367    }
368
369    /// Replace the end of the span
370    ///
371    /// ```
372    /// # use marked_yaml::{Marker, Span};
373    /// # let mut span = Span::new_blank();
374    /// assert_eq!(span.end(), None);
375    /// span.set_end(Some(Marker::new(0, 1, 1, 2)));
376    /// assert_eq!(span.end(), Some(&Marker::new(0, 1, 1, 2)));
377    /// ```
378    pub fn set_end(&mut self, end: Option<Marker>) {
379        self.end = end;
380    }
381}
382
383/// A marked YAML node
384///
385/// **NOTE**: Nodes are considered equal even if they don't come from the
386/// same place.  *i.e. their spans are ignored for equality and hashing*
387///
388/// ```
389/// use marked_yaml::parse_yaml;
390/// let node = parse_yaml(100, "{foo: bar}").unwrap();
391/// assert!(node.as_mapping().is_some());
392/// ```
393#[derive(Clone, Debug, PartialEq, Eq, Hash)]
394pub enum Node {
395    /// A YAML scalar
396    ///
397    /// You can test if a node is a scalar, and retrieve it as one if you
398    /// so wish.
399    Scalar(MarkedScalarNode),
400    /// A YAML mapping
401    ///
402    /// You can test if a node is a mapping, and retrieve it as one if you
403    /// so wish.
404    Mapping(MarkedMappingNode),
405    /// A YAML sequence
406    ///
407    /// You can test if a node is a sequence, and retrieve it as one if you
408    /// so wish.
409    Sequence(MarkedSequenceNode),
410}
411
412/// A marked scalar YAML node
413///
414/// Scalar nodes are treated by this crate as strings, though a few special
415/// values are processed into the types which YAML would ascribe.  In particular
416/// strings of the value `null`, `true`, `false`, etc. are able to present as
417/// their special values to make it a bit easier for users of the crate.
418///
419/// **NOTE**: Nodes are considered equal even if they don't come from the
420/// same place.  *i.e. their spans are ignored for equality and hashing*
421///
422/// ```
423/// use marked_yaml::{parse_yaml, Marker};
424/// let node = parse_yaml(100, "{foo: bar}").unwrap();
425/// let map = node.as_mapping().unwrap();
426/// let bar = map.get("foo").unwrap();
427/// // the "bar" string started on line 1, column 7 of source ID 100.
428/// assert_eq!(bar.span().start(), Some(&Marker::new(100, 6, 1, 7)));
429/// ```
430#[derive(Clone, Debug)]
431pub struct MarkedScalarNode {
432    span: Span,
433    value: String,
434    may_coerce: bool,
435}
436
437pub(crate) type MappingHash = LinkedHashMap<MarkedScalarNode, Node>;
438
439/// A marked YAML mapping node
440///
441/// Mapping nodes in YAML are defined as a key/value mapping where the keys are
442/// unique and always scalars, whereas values may be YAML nodes of any kind.
443///
444/// Because *some* users of this crate may need to care about insertion order
445/// we use [`hashlink::LinkedHashMap`] for this.
446///
447/// **NOTE**: Nodes are considered equal even if they don't come from the
448/// same place.  *i.e. their spans are ignored for equality and hashing*
449///
450/// ```
451/// use marked_yaml::{parse_yaml, Marker, Span};
452/// let node = parse_yaml(100, "{foo: bar}").unwrap();
453/// let map = node.as_mapping().unwrap();
454/// assert_eq!(map.span(), &Span::new_with_marks(Marker::new(100, 0, 1, 1), Marker::new(100, 9, 1, 10)));
455/// ```
456#[derive(Clone, Debug)]
457pub struct MarkedMappingNode {
458    span: Span,
459    value: MappingHash,
460}
461
462/// A marked YAML sequence node
463///
464/// Sequence nodes in YAML are simply ordered lists of YAML nodes.
465///
466/// **NOTE**: Nodes are considered equal even if they don't come from the
467/// same place.  *i.e. their spans are ignored for equality and hashing*
468///
469/// ```
470/// use marked_yaml::{parse_yaml, Marker, Span};
471/// let node = parse_yaml(100, "{foo: [bar]}").unwrap();
472/// let map = node.as_mapping().unwrap();
473/// let seq = map.get("foo").unwrap();
474/// let seq = seq.as_sequence().unwrap();
475/// assert_eq!(seq.span(), &Span::new_with_marks(Marker::new(100, 6, 1, 7), Marker::new(100, 10, 1, 11)));
476/// ```
477#[derive(Clone, Debug)]
478pub struct MarkedSequenceNode {
479    span: Span,
480    value: Vec<Node>,
481}
482
483macro_rules! basic_traits {
484    ($t:path) => {
485        impl PartialEq for $t {
486            fn eq(&self, other: &Self) -> bool {
487                self.value == other.value
488            }
489
490            #[allow(clippy::partialeq_ne_impl)]
491            fn ne(&self, other: &Self) -> bool {
492                self.value != other.value
493            }
494        }
495
496        impl Eq for $t {}
497
498        impl Hash for $t {
499            fn hash<H: Hasher>(&self, state: &mut H) {
500                self.value.hash(state);
501            }
502        }
503    };
504}
505
506basic_traits!(MarkedScalarNode);
507basic_traits!(MarkedSequenceNode);
508basic_traits!(MarkedMappingNode);
509
510impl<T> From<T> for Node
511where
512    T: Into<MarkedScalarNode>,
513{
514    fn from(value: T) -> Node {
515        Node::Scalar(value.into())
516    }
517}
518
519impl From<MarkedSequenceNode> for Node {
520    fn from(value: MarkedSequenceNode) -> Node {
521        Node::Sequence(value)
522    }
523}
524
525impl<T> From<Vec<T>> for Node
526where
527    T: Into<Node>,
528{
529    fn from(value: Vec<T>) -> Node {
530        Node::Sequence(value.into_iter().collect())
531    }
532}
533
534impl From<MarkedMappingNode> for Node {
535    fn from(value: MarkedMappingNode) -> Node {
536        Node::Mapping(value)
537    }
538}
539
540impl From<MappingHash> for Node {
541    fn from(value: MappingHash) -> Node {
542        Node::Mapping(value.into())
543    }
544}
545
546macro_rules! node_span {
547    ($t:path) => {
548        impl $t {
549            doc_comment!(
550                concat!(
551                    r#"Retrieve the Span from this node.
552
553```
554# use marked_yaml::types::*;
555let node = "#,
556                    stringify!($t),
557                    r#"::new_empty(Span::new_blank());
558assert_eq!(node.span(), &Span::new_blank());
559```"#
560                ),
561                pub fn span(&self) -> &Span {
562                    &self.span
563                }
564            );
565            doc_comment!(
566                concat!(
567                    r#"Retrieve the Span from this node mutably.
568
569```
570# use marked_yaml::types::*;
571let mut node = "#,
572                    stringify!($t),
573                    r#"::new_empty(Span::new_blank());
574node.span_mut().set_start(Some(Marker::new(0, 0, 1, 0)));
575assert_eq!(node.span().start(), Some(&Marker::new(0, 0, 1, 0)));
576```"#
577                ),
578                pub fn span_mut(&mut self) -> &mut Span {
579                    &mut self.span
580                }
581            );
582        }
583    };
584}
585
586node_span!(MarkedScalarNode);
587node_span!(MarkedMappingNode);
588node_span!(MarkedSequenceNode);
589
590impl Node {
591    /// Retrieve the Span from the contained Node
592    ///
593    /// ```
594    /// # use marked_yaml::types::*;
595    /// let node: Node = "foobar".into();
596    /// let span = node.span();
597    /// assert_eq!(span.start(), None);
598    /// ```
599    pub fn span(&self) -> &Span {
600        match self {
601            Node::Scalar(msn) => msn.span(),
602            Node::Sequence(msn) => msn.span(),
603            Node::Mapping(mmn) => mmn.span(),
604        }
605    }
606
607    /// Retrieve the Span from the contained Node, mutably
608    ///
609    /// ```
610    /// # use marked_yaml::types::*;
611    /// let mut node: Node = "foobar".into();
612    /// let mut span = node.span_mut();
613    /// assert_eq!(span.start(), None);
614    /// span.set_start(Some(Marker::new(0, 0, 1, 0)));
615    /// assert_eq!(span.start(), Some(&Marker::new(0, 0, 1, 0)));
616    /// ```
617    pub fn span_mut(&mut self) -> &mut Span {
618        match self {
619            Node::Scalar(msn) => msn.span_mut(),
620            Node::Sequence(msn) => msn.span_mut(),
621            Node::Mapping(mmn) => mmn.span_mut(),
622        }
623    }
624
625    /// Retrieve the scalar from this node if there is one
626    ///
627    /// ```
628    /// # use marked_yaml::types::*;
629    /// let node: Node = "foobar".into();
630    /// let scalar = node.as_scalar();
631    /// assert!(scalar.is_some());
632    /// ```
633    pub fn as_scalar(&self) -> Option<&MarkedScalarNode> {
634        match self {
635            Node::Scalar(msn) => Some(msn),
636            _ => None,
637        }
638    }
639
640    /// Retrieve the sequence from this node if there is one
641    ///
642    /// ```
643    /// # use marked_yaml::types::*;
644    /// let node: Node = vec!["foobar"].into();
645    /// let sequence = node.as_sequence();
646    /// assert!(sequence.is_some());
647    /// ```
648    pub fn as_sequence(&self) -> Option<&MarkedSequenceNode> {
649        match self {
650            Node::Sequence(msn) => Some(msn),
651            _ => None,
652        }
653    }
654
655    /// Retrieve the mapping from this node if there is one
656    ///
657    /// ```
658    /// # use marked_yaml::*;
659    /// let node: Node = parse_yaml(0, "{foobar: baz}").unwrap();
660    /// let mapping = node.as_mapping();
661    /// assert!(mapping.is_some());
662    /// ```
663    pub fn as_mapping(&self) -> Option<&MarkedMappingNode> {
664        match self {
665            Node::Mapping(mmn) => Some(mmn),
666            _ => None,
667        }
668    }
669
670    /// Retrieve the scalar from this node if there is one, mutably
671    ///
672    /// ```
673    /// # use marked_yaml::types::*;
674    /// let mut node: Node = "foobar".into();
675    /// let mut scalar = node.as_scalar_mut();
676    /// assert!(scalar.is_some());
677    /// ```
678    pub fn as_scalar_mut(&mut self) -> Option<&mut MarkedScalarNode> {
679        match self {
680            Node::Scalar(msn) => Some(msn),
681            _ => None,
682        }
683    }
684
685    /// Retrieve the sequence from this node if there is one, mutably
686    ///
687    /// ```
688    /// # use marked_yaml::types::*;
689    /// let mut node: Node = vec!["foobar"].into();
690    /// let mut sequence = node.as_sequence_mut();
691    /// assert!(sequence.is_some());
692    /// ```
693    pub fn as_sequence_mut(&mut self) -> Option<&mut MarkedSequenceNode> {
694        match self {
695            Node::Sequence(msn) => Some(msn),
696            _ => None,
697        }
698    }
699
700    /// Retrieve the mapping from this node if there is one, mutably
701    ///
702    /// ```
703    /// # use marked_yaml::*;
704    /// let mut node: Node = parse_yaml(0, "{foobar: baz}").unwrap();
705    /// let mut mapping = node.as_mapping_mut();
706    /// assert!(mapping.is_some());
707    /// ```
708    pub fn as_mapping_mut(&mut self) -> Option<&mut MarkedMappingNode> {
709        match self {
710            Node::Mapping(mmn) => Some(mmn),
711            _ => None,
712        }
713    }
714}
715
716impl MarkedScalarNode {
717    /// Create a new scalar node with no value
718    ///
719    /// ```
720    /// # use marked_yaml::types::*;
721    /// let node = MarkedScalarNode::new_empty(Span::new_blank());
722    /// ```
723    pub fn new_empty(span: Span) -> Self {
724        Self {
725            span,
726            value: String::new(),
727            may_coerce: true,
728        }
729    }
730
731    /// Create a new scalar node
732    ///
733    /// ```
734    /// # use marked_yaml::types::*;
735    /// let node = MarkedScalarNode::new(Span::new_blank(), "foobar");
736    /// ```
737    pub fn new<'a, S: Into<Cow<'a, str>>>(span: Span, content: S) -> Self {
738        Self {
739            span,
740            value: content.into().into_owned(),
741            may_coerce: true,
742        }
743    }
744
745    /// Treat the scalar node as a string
746    ///
747    /// Since scalars are always stringish, this is always safe.
748    ///
749    /// ```
750    /// # use marked_yaml::types::*;
751    /// let node: MarkedScalarNode = "foobar".into();
752    /// assert_eq!(node.as_str(), "foobar");
753    /// ```
754    pub fn as_str(&self) -> &str {
755        self.value.as_str()
756    }
757
758    /// Enable or disable permission to coerce values
759    ///
760    /// The various [`as_bool()`][Self::as_bool()] and other methods
761    /// which can coerce a string can be forced to always deny
762    /// coercion.
763    ///
764    #[cfg_attr(
765        feature = "serde",
766        doc = r#"
767Note: this also applies for deserializing nodes via serde.
768
769"#
770    )]
771    /// ```
772    /// # use marked_yaml::types::*;
773    /// let mut node: MarkedScalarNode = "true".into();
774    /// assert_eq!(node.as_bool(), Some(true));
775    /// node.set_coerce(false);
776    /// assert_eq!(node.as_bool(), None);
777    /// ```
778    pub fn set_coerce(&mut self, may_coerce: bool) {
779        self.may_coerce = may_coerce;
780    }
781
782    /// Retrieve whether or not this node is set to be coerceable
783    ///
784    /// The various [`as_bool()`][Self::as_bool()] and other methods
785    /// which can coerce a string can be forced to deny coercion.
786    ///
787    #[cfg_attr(
788        feature = "serde",
789        doc = r#"
790Note: this also applies for deserializing nodes via serde.
791
792"#
793    )]
794    /// ```
795    /// # use marked_yaml::types::*;
796    /// let mut node: MarkedScalarNode = "true".into();
797    /// assert_eq!(node.as_bool(), Some(true));
798    /// assert_eq!(node.may_coerce(), true);
799    /// node.set_coerce(false);
800    /// assert_eq!(node.as_bool(), None);
801    /// assert_eq!(node.may_coerce(), false);
802    /// ```
803    pub fn may_coerce(&self) -> bool {
804        self.may_coerce
805    }
806
807    /// Treat the scalar node as a boolean
808    ///
809    /// If the scalar contains any of the following then it is true:
810    ///
811    /// * `true`
812    /// * `True`
813    /// * `TRUE`
814    ///
815    /// The following are considered false:
816    ///
817    /// * `false`
818    /// * `False`
819    /// * `FALSE`
820    ///
821    /// Everything else is not a boolean and so will return None
822    ///
823    /// Note: If you have done [`.set_coerce(false)`](MarkedScalarNode::set_coerce())
824    /// then no matter the string's value, this will return `None`.
825    ///
826    /// ```
827    /// # use marked_yaml::types::*;
828    /// let node: MarkedScalarNode = "true".into();
829    /// assert_eq!(node.as_bool(), Some(true));
830    /// let node: MarkedScalarNode = "FALSE".into();
831    /// assert_eq!(node.as_bool(), Some(false));
832    /// let node: MarkedScalarNode = "NO".into(); // YAML boolean, but not for us
833    /// assert_eq!(node.as_bool(), None);
834    /// let mut node: MarkedScalarNode = "true".into();
835    /// node.set_coerce(false);
836    /// assert_eq!(node.as_bool(), None);
837    /// ```
838    pub fn as_bool(&self) -> Option<bool> {
839        if self.may_coerce {
840            match self.value.as_str() {
841                "true" | "True" | "TRUE" => Some(true),
842                "false" | "False" | "FALSE" => Some(false),
843                _ => None,
844            }
845        } else {
846            None
847        }
848    }
849
850    #[cfg(feature = "serde")]
851    pub(crate) fn is_empty_scalar(&self) -> bool {
852        self.value.is_empty() && self.may_coerce
853    }
854}
855
856impl<'a> From<&'a str> for MarkedScalarNode {
857    /// Convert from any borrowed string into a node
858    ///
859    /// ```
860    /// # use marked_yaml::types::*;
861    /// let node: MarkedScalarNode = "foobar".into();
862    /// ```
863    fn from(value: &'a str) -> Self {
864        Self::new(Span::new_blank(), value)
865    }
866}
867
868impl From<String> for MarkedScalarNode {
869    /// Convert from any owned string into a node
870    ///
871    /// ```
872    /// # use marked_yaml::types::*;
873    /// let foobar = "foobar".to_string();
874    /// let node: MarkedScalarNode = foobar.into();
875    /// ```
876    fn from(value: String) -> Self {
877        Self::new(Span::new_blank(), value)
878    }
879}
880
881impl From<bool> for MarkedScalarNode {
882    /// Convert from a boolean into a node
883    ///
884    /// ```
885    /// # use marked_yaml::types::*;
886    /// let node = MarkedScalarNode::from(true);
887    /// ```
888    fn from(value: bool) -> Self {
889        if value {
890            "true".into()
891        } else {
892            "false".into()
893        }
894    }
895}
896
897macro_rules! scalar_from_to_number {
898    ($t:ident, $as:ident) => {
899        scalar_from_to_number!($t, $as, 0);
900    };
901
902    ($t:ident, $as:ident, $zero:expr) => {
903        impl From<$t> for MarkedScalarNode {
904            doc_comment!(
905                concat!(
906                    "Convert from ",
907                    stringify!($t),
908                    r#" into a node
909
910```
911# use marked_yaml::types::*;
912let value: "#,
913                    stringify!($t),
914                    " = ",
915                    stringify!($zero),
916                    r#";
917let node: MarkedScalarNode = value.into();
918assert_eq!(&*node, "0");
919```"#
920                ),
921                fn from(value: $t) -> Self {
922                    format!("{}", value).into()
923                }
924            );
925        }
926
927        impl MarkedScalarNode {
928            doc_comment!(
929                concat!(
930                    "Treat the scalar node as ",
931                    stringify!($t),
932                    r#".
933
934If this scalar node's value can be represented properly as
935a number of the right kind then return it.  This is essentially
936a shortcut for using the `FromStr` trait on the return value of
937`.as_str()`.
938
939Note, this honours the setting of [`MarkedScalarNode::set_coerce()`]
940
941```
942# use marked_yaml::types::*;
943let mut node: MarkedScalarNode = "0".into();
944assert_eq!(node.as_"#,
945                    stringify!($t),
946                    r#"(), Some(0"#,
947                    stringify!($t),
948                    r#"));
949node.set_coerce(false);
950assert_eq!(node.as_"#,
951                    stringify!($t),
952                    r#"(), None);
953```"#
954                ),
955                pub fn $as(&self) -> Option<$t> {
956                    if self.may_coerce {
957                        use std::str::FromStr;
958                        $t::from_str(&self.value).ok()
959                    } else {
960                        None
961                    }
962                }
963            );
964        }
965    };
966}
967
968scalar_from_to_number!(i8, as_i8);
969scalar_from_to_number!(i16, as_i16);
970scalar_from_to_number!(i32, as_i32);
971scalar_from_to_number!(i64, as_i64);
972scalar_from_to_number!(i128, as_i128);
973scalar_from_to_number!(isize, as_isize);
974scalar_from_to_number!(u8, as_u8);
975scalar_from_to_number!(u16, as_u16);
976scalar_from_to_number!(u32, as_u32);
977scalar_from_to_number!(u64, as_u64);
978scalar_from_to_number!(u128, as_u128);
979scalar_from_to_number!(usize, as_usize);
980scalar_from_to_number!(f32, as_f32, 0.0);
981scalar_from_to_number!(f64, as_f64, 0.0);
982
983impl Deref for MarkedScalarNode {
984    type Target = str;
985
986    /// Borrow the string value inside this scalar node
987    ///
988    /// ```
989    /// # use marked_yaml::types::*;
990    /// # use std::str::FromStr;
991    /// let truth: MarkedScalarNode = "true".into();
992    /// assert!(bool::from_str(&truth).unwrap())
993    /// ```
994    fn deref(&self) -> &Self::Target {
995        &self.value
996    }
997}
998
999impl Borrow<str> for MarkedScalarNode {
1000    fn borrow(&self) -> &str {
1001        &self.value
1002    }
1003}
1004
1005impl MarkedSequenceNode {
1006    /// Create a new empty sequence node
1007    ///
1008    /// ```
1009    /// # use marked_yaml::types::*;
1010    /// let node = MarkedSequenceNode::new_empty(Span::new_blank());
1011    /// ```
1012    pub fn new_empty(span: Span) -> Self {
1013        Self {
1014            span,
1015            value: Vec::new(),
1016        }
1017    }
1018
1019    /// Create a new sequence node from a vector of nodes
1020    ///
1021    /// ```
1022    /// # use marked_yaml::types::*;
1023    /// let node = MarkedSequenceNode::new(Span::new_blank(), Vec::new());
1024    /// ```
1025    pub fn new(span: Span, value: Vec<Node>) -> Self {
1026        Self { span, value }
1027    }
1028
1029    /// Get the node at the given index
1030    ///
1031    /// If the index is invalid then None will be returned
1032    ///
1033    /// ```
1034    /// # use marked_yaml::types::*;
1035    /// let seq: MarkedSequenceNode = vec!["foobar"].into_iter().collect();
1036    /// assert_eq!(seq.get_node(0)
1037    ///     .and_then(Node::as_scalar)
1038    ///     .map(MarkedScalarNode::as_str)
1039    ///     .unwrap(),
1040    ///     "foobar");
1041    pub fn get_node(&self, index: usize) -> Option<&Node> {
1042        self.value.get(index)
1043    }
1044
1045    /// Get the scalar at the given index
1046    ///
1047    /// If the index is invalid, or the node at that index is not a scalar
1048    /// node, then None will be returned.
1049    ///
1050    /// ```
1051    /// # use marked_yaml::types::*;
1052    /// let seq: MarkedSequenceNode = vec!["foobar"].into_iter().collect();
1053    /// assert_eq!(seq.get_scalar(0)
1054    ///     .map(MarkedScalarNode::as_str)
1055    ///     .unwrap(),
1056    ///     "foobar");
1057    /// ```
1058    pub fn get_scalar(&self, index: usize) -> Option<&MarkedScalarNode> {
1059        self.get_node(index).and_then(Node::as_scalar)
1060    }
1061
1062    /// Get the sequence at the given index
1063    ///
1064    /// If the index is invalid, or the node at that index is not a sequence
1065    /// node, then None will be returned.
1066    ///
1067    /// ```
1068    /// # use marked_yaml::types::*;
1069    /// let seq: MarkedSequenceNode = vec![vec!["foobar"]].into_iter().collect();
1070    /// assert_eq!(seq.get_sequence(0)
1071    ///     .and_then(|s| s.get_scalar(0))
1072    ///     .map(MarkedScalarNode::as_str)
1073    ///     .unwrap(),
1074    ///     "foobar");
1075    /// ```
1076    pub fn get_sequence(&self, index: usize) -> Option<&MarkedSequenceNode> {
1077        self.get_node(index).and_then(Node::as_sequence)
1078    }
1079
1080    /// Get the mapping at the given index
1081    ///
1082    /// If the index is invalid, or the node at that index is not a mapping
1083    /// node, then None will be returned.
1084    ///
1085    /// ```
1086    /// # use marked_yaml::types::*;
1087    /// # use hashlink::LinkedHashMap;
1088    /// # let map: LinkedHashMap<MarkedScalarNode, Node> = LinkedHashMap::new();
1089    /// let seq: MarkedSequenceNode = vec![map].into_iter().collect();
1090    /// assert!(seq.get_mapping(0).is_some());
1091    /// ```
1092    pub fn get_mapping(&self, index: usize) -> Option<&MarkedMappingNode> {
1093        self.get_node(index).and_then(Node::as_mapping)
1094    }
1095}
1096
1097impl Deref for MarkedSequenceNode {
1098    type Target = Vec<Node>;
1099    fn deref(&self) -> &Self::Target {
1100        &self.value
1101    }
1102}
1103
1104impl DerefMut for MarkedSequenceNode {
1105    fn deref_mut(&mut self) -> &mut Self::Target {
1106        &mut self.value
1107    }
1108}
1109
1110impl<T> FromIterator<T> for MarkedSequenceNode
1111where
1112    T: Into<Node>,
1113{
1114    /// Allow collecting things into a sequence node
1115    ///
1116    /// ```
1117    /// # use marked_yaml::types::*;
1118    /// let node: MarkedSequenceNode = vec!["hello", "world"].into_iter().collect();
1119    /// ```
1120    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
1121        let value: Vec<Node> = iter.into_iter().map(Into::into).collect();
1122        let span = match value.len() {
1123            0 => Span::new_blank(),
1124            1 => *value[0].span(),
1125            _ => Span {
1126                start: value[0].span().start,
1127                end: value[value.len() - 1].span().end,
1128            },
1129        };
1130        Self { span, value }
1131    }
1132}
1133
1134impl<T> From<Vec<T>> for MarkedSequenceNode
1135where
1136    T: Into<Node>,
1137{
1138    /// Allow converting from vectors of things to sequence nodes
1139    ///
1140    /// ```
1141    /// # use marked_yaml::types::*;
1142    /// let node: MarkedSequenceNode = vec!["hello", "world"].into();
1143    /// ```
1144    fn from(value: Vec<T>) -> Self {
1145        let value: Vec<Node> = value.into_iter().map(Into::into).collect();
1146        let span = match value.len() {
1147            0 => Span::new_blank(),
1148            1 => *value[0].span(),
1149            _ => {
1150                let start = value[0].span().start;
1151                let end = value[value.len() - 1].span().end;
1152                Span { start, end }
1153            }
1154        };
1155        Self { span, value }
1156    }
1157}
1158
1159impl MarkedMappingNode {
1160    /// Create a new empty mapping node
1161    ///
1162    /// ```
1163    /// # use marked_yaml::types::*;
1164    /// let node = MarkedMappingNode::new_empty(Span::new_blank());
1165    /// ```
1166    pub fn new_empty(span: Span) -> Self {
1167        Self {
1168            span,
1169            value: LinkedHashMap::new(),
1170        }
1171    }
1172
1173    /// Create a new mapping node from the given hash table
1174    ///
1175    /// ```
1176    /// # use marked_yaml::types::*;
1177    /// # use hashlink::LinkedHashMap;
1178    /// let node = MarkedMappingNode::new(Span::new_blank(), LinkedHashMap::new());
1179    /// ```
1180    pub fn new(span: Span, value: MappingHash) -> Self {
1181        Self { span, value }
1182    }
1183
1184    /// Get the node for the given string key
1185    ///
1186    /// If the index is not found then None is returned.
1187    ///
1188    /// ```
1189    /// # use marked_yaml::types::*;
1190    /// # use marked_yaml::parse_yaml;
1191    /// let node = parse_yaml(0, "{key: value}").unwrap();
1192    /// let map = node.as_mapping().unwrap();
1193    /// assert_eq!(map.get_node("key")
1194    ///     .and_then(Node::as_scalar)
1195    ///     .map(MarkedScalarNode::as_str)
1196    ///     .unwrap(),
1197    ///     "value");
1198    /// ```
1199    pub fn get_node(&self, index: &str) -> Option<&Node> {
1200        self.value.get(index)
1201    }
1202
1203    /// Get the scalar for the given string key
1204    ///
1205    /// If the key is not found, or the node for that key is not a scalar
1206    /// node, then None will be returned.
1207    ///
1208    /// ```
1209    /// # use marked_yaml::types::*;
1210    /// # use marked_yaml::parse_yaml;
1211    /// let node = parse_yaml(0, "{key: value}").unwrap();
1212    /// let map = node.as_mapping().unwrap();
1213    /// assert_eq!(map.get_scalar("key")
1214    ///     .map(MarkedScalarNode::as_str)
1215    ///     .unwrap(),
1216    ///     "value");
1217    /// ```
1218    pub fn get_scalar(&self, index: &str) -> Option<&MarkedScalarNode> {
1219        self.get_node(index).and_then(Node::as_scalar)
1220    }
1221
1222    /// Get the sequence at the given index
1223    ///
1224    /// If the key is not found, or the node for that key is not a sequence
1225    /// node, then None will be returned.
1226    ///
1227    /// ```
1228    /// # use marked_yaml::types::*;
1229    /// # use marked_yaml::parse_yaml;
1230    /// let node = parse_yaml(0, "{key: [value]}").unwrap();
1231    /// let map = node.as_mapping().unwrap();
1232    /// assert_eq!(map.get_sequence("key")
1233    ///     .and_then(|s| s.get_scalar(0))
1234    ///     .map(MarkedScalarNode::as_str)
1235    ///     .unwrap(),
1236    ///     "value");
1237    /// ```
1238    pub fn get_sequence(&self, index: &str) -> Option<&MarkedSequenceNode> {
1239        self.get_node(index).and_then(Node::as_sequence)
1240    }
1241
1242    /// Get the mapping at the given index
1243    ///
1244    /// If the key is not found, or the node for that key is not a mapping
1245    /// node, then None will be returned.
1246    ///
1247    /// ```
1248    /// # use marked_yaml::types::*;
1249    /// # use marked_yaml::parse_yaml;
1250    /// let node = parse_yaml(0, "{key: {inner: value}}").unwrap();
1251    /// let map = node.as_mapping().unwrap();
1252    /// assert_eq!(map.get_mapping("key")
1253    ///     .and_then(|m| m.get_scalar("inner"))
1254    ///     .map(MarkedScalarNode::as_str)
1255    ///     .unwrap(),
1256    ///     "value");
1257    /// ```
1258    pub fn get_mapping(&self, index: &str) -> Option<&MarkedMappingNode> {
1259        self.get_node(index).and_then(Node::as_mapping)
1260    }
1261}
1262
1263impl Deref for MarkedMappingNode {
1264    type Target = MappingHash;
1265    fn deref(&self) -> &Self::Target {
1266        &self.value
1267    }
1268}
1269
1270impl DerefMut for MarkedMappingNode {
1271    fn deref_mut(&mut self) -> &mut Self::Target {
1272        &mut self.value
1273    }
1274}
1275
1276impl From<MappingHash> for MarkedMappingNode {
1277    fn from(value: MappingHash) -> Self {
1278        Self::new(Span::new_blank(), value)
1279    }
1280}
1281
1282impl<T, U> FromIterator<(T, U)> for MarkedMappingNode
1283where
1284    T: Into<MarkedScalarNode>,
1285    U: Into<Node>,
1286{
1287    /// Allow collecting into a mapping node
1288    ///
1289    /// ```
1290    /// # use marked_yaml::types::*;
1291    /// # use std::collections::HashMap;
1292    /// # let mut hashmap = HashMap::new();
1293    /// hashmap.insert("hello", vec!["world".to_string()]);
1294    /// hashmap.insert("key", vec!["value".to_string()]);
1295    /// let node: MarkedMappingNode = hashmap.into_iter().collect();
1296    /// ```
1297    fn from_iter<I: IntoIterator<Item = (T, U)>>(iter: I) -> Self {
1298        let value: MappingHash = iter
1299            .into_iter()
1300            .map(|(k, v)| (k.into(), v.into()))
1301            .collect();
1302        let span = match value.len() {
1303            0 => Span::new_blank(),
1304            // Unwrap is safe because there's at least one span here
1305            1 => {
1306                let (k, v) = value.iter().next().unwrap();
1307                Span {
1308                    start: k.span().start,
1309                    end: v.span().end,
1310                }
1311            }
1312            _ => {
1313                let mut iter = value.iter();
1314                // Unwraps save because there's at least two spans here
1315                let start = iter.next().unwrap().0.span().start;
1316                let end = iter.next_back().unwrap().1.span().end;
1317                Span { start, end }
1318            }
1319        };
1320        Self { span, value }
1321    }
1322}
1323
1324/// Errors which could be encountered while converting from a `yaml_rust::Yaml`
1325#[derive(Debug, PartialEq, Eq)]
1326pub enum YamlConversionError {
1327    /// An alias was encountered while converting
1328    Alias,
1329    /// A BadValue was encountered while converting
1330    BadValue,
1331    /// A non-scalar value was encountered when a scalar was expected
1332    NonScalar,
1333}
1334
1335impl TryFrom<YamlNode> for MarkedScalarNode {
1336    type Error = YamlConversionError;
1337
1338    fn try_from(value: YamlNode) -> Result<Self, Self::Error> {
1339        match value {
1340            YamlNode::Alias(_) => Err(YamlConversionError::Alias),
1341            YamlNode::Array(_) => Err(YamlConversionError::NonScalar),
1342            YamlNode::BadValue => Err(YamlConversionError::BadValue),
1343            YamlNode::Boolean(b) => Ok(b.into()),
1344            YamlNode::Hash(_) => Err(YamlConversionError::NonScalar),
1345            YamlNode::Integer(i) => Ok(i.into()),
1346            YamlNode::Null => Ok("null".into()),
1347            YamlNode::Real(s) => Ok(s.into()),
1348            YamlNode::String(s) => Ok(s.into()),
1349        }
1350    }
1351}
1352
1353impl TryFrom<YamlNode> for Node {
1354    type Error = YamlConversionError;
1355
1356    /// Convert from any `yaml_rust::Yaml` to a Node
1357    ///
1358    /// ```
1359    /// # use yaml_rust::YamlLoader;
1360    /// # use marked_yaml::types::*;
1361    /// # use std::convert::TryFrom;
1362    /// let docs = YamlLoader::load_from_str("[1, 2]").unwrap();
1363    /// let yaml = docs.into_iter().next().unwrap();
1364    /// let node = Node::try_from(yaml).unwrap();
1365    /// ```
1366    fn try_from(value: YamlNode) -> Result<Self, Self::Error> {
1367        match value {
1368            YamlNode::Array(arr) => Ok(Node::Sequence(
1369                arr.into_iter()
1370                    .map(Node::try_from)
1371                    .collect::<Result<MarkedSequenceNode, Self::Error>>()?,
1372            )),
1373            YamlNode::Hash(h) => Ok(Node::Mapping(
1374                h.into_iter()
1375                    .map(|(k, v)| Ok((MarkedScalarNode::try_from(k)?, Node::try_from(v)?)))
1376                    .collect::<Result<MarkedMappingNode, Self::Error>>()?,
1377            )),
1378            scalar => Ok(Node::Scalar(MarkedScalarNode::try_from(scalar)?)),
1379        }
1380    }
1381}
1382
1383impl From<MarkedScalarNode> for YamlNode {
1384    fn from(value: MarkedScalarNode) -> Self {
1385        YamlNode::String(value.value)
1386    }
1387}
1388
1389impl From<MarkedSequenceNode> for YamlNode {
1390    fn from(value: MarkedSequenceNode) -> Self {
1391        YamlNode::Array(value.value.into_iter().map(Into::into).collect())
1392    }
1393}
1394
1395impl From<MarkedMappingNode> for YamlNode {
1396    fn from(value: MarkedMappingNode) -> Self {
1397        YamlNode::Hash(
1398            value
1399                .value
1400                .into_iter()
1401                .map(|(k, v)| (k.into(), v.into()))
1402                .collect(),
1403        )
1404    }
1405}
1406
1407impl From<Node> for YamlNode {
1408    fn from(value: Node) -> Self {
1409        match value {
1410            Node::Scalar(msn) => msn.into(),
1411            Node::Sequence(msn) => msn.into(),
1412            Node::Mapping(mmn) => mmn.into(),
1413        }
1414    }
1415}
1416
1417#[cfg(test)]
1418mod test {
1419    use super::super::*;
1420    use super::*;
1421
1422    #[test]
1423    fn basic_marker_checks() {
1424        let marker = Marker::new(0, 3, 1, 2);
1425        assert_eq!(marker.source(), 0);
1426        assert_eq!(marker.character(), 3);
1427        assert_eq!(marker.line(), 1);
1428        assert_eq!(marker.column(), 2);
1429        assert_eq!(format!("{}", marker), "1:2");
1430        let rendered = marker.render(|n| {
1431            assert_eq!(n, 0);
1432            "name"
1433        });
1434        assert_eq!(format!("{}", rendered), "name:1:2");
1435    }
1436
1437    #[test]
1438    fn basic_span_checks() {
1439        let span = Span::new_blank();
1440        assert_eq!(span.start(), None);
1441        assert_eq!(span.end(), None);
1442        let mark = Marker::new(0, 1, 1, 2);
1443        let mark2 = Marker::new(3, 9, 4, 5);
1444        let span = Span::new_start(mark);
1445        assert_eq!(span.start(), Some(&mark));
1446        assert_eq!(span.end(), None);
1447        let span = Span::new_with_marks(mark, mark2);
1448        assert_eq!(span.start(), Some(&mark));
1449        assert_eq!(span.end(), Some(&mark2));
1450    }
1451
1452    #[test]
1453    fn basic_explore_load_test() {
1454        let node = parse_yaml(0, include_str!("../examples/everything.yaml")).unwrap();
1455        let map = node.as_mapping().unwrap();
1456        assert_eq!(node.as_scalar(), None);
1457        assert_eq!(node.as_sequence(), None);
1458        assert_eq!(map.get_node("XXX NOT PRESENT XXX"), None);
1459        assert_eq!(map.get_scalar("mapping"), None);
1460        assert_eq!(map.get_sequence("mapping"), None);
1461        assert_eq!(map.get_mapping("simple"), None);
1462        // This actually uses .eq()
1463        assert_ne!(map.get_scalar("boolean1"), map.get_scalar("boolean2"));
1464        // Whereas this uses .ne()
1465        assert!(map.get_scalar("boolean1") != map.get_scalar("boolean2"));
1466        // Now check the spans
1467        assert_eq!(node.span(), map.span());
1468        let seq = map.get_sequence("heterogenous").unwrap();
1469        assert_eq!(seq.span().start(), Some(&Marker::new(0, 431, 24, 3)));
1470        assert_eq!(seq.span(), map.get_node("heterogenous").unwrap().span());
1471        // Helpers for the sequence node
1472        assert_eq!(seq.get_node(0), seq.first());
1473        assert_ne!(seq.get_node(0), None);
1474        assert_ne!(seq.get_scalar(0), None);
1475        assert_ne!(seq.get_mapping(1), None);
1476        assert_ne!(seq.get_sequence(2), None);
1477    }
1478
1479    #[test]
1480    fn basic_scalar_features() {
1481        let scalar1 = MarkedScalarNode::new(Span::new_blank(), "");
1482        let scalar2 = MarkedScalarNode::new_empty(Span::new_blank());
1483        assert_eq!(scalar1, scalar2);
1484        assert_eq!(scalar1.as_str(), "");
1485        assert_eq!(scalar1.as_bool(), None);
1486        assert_eq!(scalar1.as_usize(), None);
1487        let truth: MarkedScalarNode = "true".into();
1488        assert_eq!(truth.as_bool(), Some(true));
1489        let falsehood: MarkedScalarNode = "false".to_string().into();
1490        assert_eq!(falsehood.as_bool(), Some(false));
1491        assert_eq!(truth, true.into());
1492        assert_eq!(falsehood, false.into());
1493        let zero: MarkedScalarNode = "0".into();
1494        assert_eq!(zero.as_usize(), Some(0));
1495        assert_eq!(zero, 0usize.into());
1496        assert_eq!(&*zero, "0");
1497    }
1498
1499    #[test]
1500    fn basic_sequence_features() {
1501        // For features not covered by other tests
1502        let mut seq = MarkedSequenceNode::new_empty(Span::new_blank());
1503        let seq2: MarkedSequenceNode = vec!["foo"].into_iter().collect();
1504        let scalar: MarkedScalarNode = "foo".into();
1505        seq.push(Node::from(scalar));
1506        assert_eq!(seq, seq2);
1507        assert_eq!(seq, vec!["foo"].into());
1508        let seq3: MarkedSequenceNode = vec!["foo", "bar"].into_iter().collect();
1509        seq.push(Node::from("bar"));
1510        assert_eq!(seq, seq3);
1511        assert_eq!(seq, vec!["foo", "bar"].into());
1512    }
1513
1514    #[test]
1515    fn basic_mapping_features() {
1516        // For features not covered by other tests
1517        let mut map = MarkedMappingNode::new_empty(Span::new_blank());
1518        let mut hash = MappingHash::new();
1519        hash.insert("foo".into(), "bar".into());
1520        let map2 = MarkedMappingNode::from(hash);
1521        map.insert("foo".into(), "bar".into());
1522        assert_eq!(map, map2);
1523        assert_eq!(map.get("foo").unwrap().as_scalar().unwrap().as_str(), "bar");
1524        let map3: MarkedMappingNode = vec![("foo", "bar")].into_iter().collect();
1525        assert_eq!(map, map3);
1526        map.insert("baz".into(), "meta".into());
1527        let map4: MarkedMappingNode = vec![("foo", "bar"), ("baz", "meta")].into_iter().collect();
1528        assert_eq!(map, map4);
1529    }
1530
1531    #[test]
1532    fn extra_node_impls() {
1533        let node = Node::from(vec!["foo"]);
1534        assert_ne!(node.as_sequence(), None);
1535        let node = Node::from(MappingHash::new());
1536        assert!(node.as_mapping().unwrap().is_empty());
1537    }
1538
1539    #[test]
1540    fn yaml_conversions() {
1541        use yaml_rust::YamlLoader;
1542        let mut everything =
1543            YamlLoader::load_from_str(include_str!("../examples/everything.yaml")).unwrap();
1544        let everything = everything.pop().unwrap();
1545        let node = Node::try_from(everything.clone()).unwrap();
1546        assert!(node.as_mapping().is_some());
1547        let badscalar = MarkedScalarNode::try_from(everything);
1548        assert_eq!(badscalar, Err(YamlConversionError::NonScalar));
1549        let badscalar = MarkedScalarNode::try_from(YamlNode::BadValue);
1550        assert_eq!(badscalar, Err(YamlConversionError::BadValue));
1551        let badscalar = MarkedScalarNode::try_from(YamlNode::Array(vec![]));
1552        assert_eq!(badscalar, Err(YamlConversionError::NonScalar));
1553    }
1554
1555    fn flatten(node: YamlNode) -> YamlNode {
1556        match node {
1557            YamlNode::Array(arr) => YamlNode::Array(arr.into_iter().map(flatten).collect()),
1558            YamlNode::Boolean(b) => {
1559                YamlNode::String((if b { "true" } else { "false" }).to_string())
1560            }
1561            YamlNode::Hash(h) => YamlNode::Hash(
1562                h.into_iter()
1563                    .map(|(k, v)| (flatten(k), flatten(v)))
1564                    .collect(),
1565            ),
1566            YamlNode::Integer(i) => YamlNode::String(format!("{}", i)),
1567            YamlNode::Null => YamlNode::String("null".to_string()),
1568            YamlNode::Real(r) => YamlNode::String(r),
1569            other => other,
1570        }
1571    }
1572
1573    #[test]
1574    fn back_yaml_conversion() {
1575        use yaml_rust::YamlLoader;
1576        let mut everything =
1577            YamlLoader::load_from_str(include_str!("../examples/everything.yaml")).unwrap();
1578        let everything = everything.pop().unwrap();
1579        let node = Node::try_from(everything.clone()).unwrap();
1580        let other: YamlNode = node.into();
1581        let flat = flatten(everything);
1582        assert_eq!(flat, other);
1583    }
1584}