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}