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}