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