1use crate::chars::{
11 b_non_content, decode_escape, ns_anchor_char, ns_plain_char, ns_plain_first, s_white,
12};
13use crate::combinator::neg_lookahead;
14use crate::combinator::{
15 Context, Parser, Reply, State, char_parser, many0, many1, seq, token, wrap_tokens,
16};
17use crate::structure::{
18 c_forbidden, c_ns_properties, l_empty, s_flow_folded, s_flow_line_prefix_ge, s_separate,
19 s_separate_ge,
20};
21use crate::token::{Code, Token};
22
23#[must_use]
31pub fn c_ns_alias_node<'i>() -> Parser<'i> {
32 wrap_tokens(
33 Code::BeginAlias,
34 Code::EndAlias,
35 seq(
36 token(Code::Indicator, char_parser('*')),
37 token(Code::Meta, many1(ns_anchor_char())),
38 ),
39 )
40}
41
42#[must_use]
48pub fn e_scalar<'i>() -> Parser<'i> {
49 Box::new(|state| Reply::Success {
50 tokens: Vec::new(),
51 state,
52 })
53}
54
55#[must_use]
57pub fn e_node<'i>() -> Parser<'i> {
58 Box::new(|state| Reply::Success {
59 tokens: Vec::new(),
60 state,
61 })
62}
63
64#[must_use]
73pub fn nb_double_char<'i>() -> Parser<'i> {
74 Box::new(|state| {
75 let Some(ch) = state.peek() else {
76 return Reply::Failure;
77 };
78 match ch {
79 '"' => Reply::Failure,
80 '\\' => {
81 let start_pos = state.pos;
83 let start_input = state.input;
84 let after_backslash = state.advance('\\');
85 let rest = after_backslash.input;
86 match decode_escape(rest) {
87 None => Reply::Failure,
88 Some((_decoded, bytes_consumed)) => {
89 let mut s = after_backslash;
91 let mut consumed = 0;
92 for ec in rest.chars() {
93 if consumed >= bytes_consumed {
94 break;
95 }
96 s = s.advance(ec);
97 consumed += ec.len_utf8();
98 }
99 let total_bytes = s.pos.byte_offset - start_pos.byte_offset;
100 let text = &start_input[..total_bytes];
101 Reply::Success {
103 tokens: vec![Token {
104 code: Code::Text,
105 pos: start_pos,
106 text,
107 }],
108 state: s,
109 }
110 }
111 }
112 }
113 _ => {
115 if matches!(ch, '\n' | '\r') {
117 return Reply::Failure;
118 }
119 if ch == '\u{FEFF}' {
121 return Reply::Failure;
122 }
123 let start_pos = state.pos;
124 let start_input = state.input;
125 let new_state = state.advance(ch);
126 let byte_len = ch.len_utf8();
127 Reply::Success {
128 tokens: vec![Token {
129 code: Code::Text,
130 pos: start_pos,
131 text: &start_input[..byte_len],
132 }],
133 state: new_state,
134 }
135 }
136 }
137 })
138}
139
140#[must_use]
142pub fn ns_double_char<'i>() -> Parser<'i> {
143 Box::new(|state| {
144 let Some(ch) = state.peek() else {
145 return Reply::Failure;
146 };
147 if matches!(ch, ' ' | '\t') {
148 return Reply::Failure;
149 }
150 nb_double_char()(state)
151 })
152}
153
154fn nb_double_one_line<'i>() -> Parser<'i> {
156 many0(nb_double_char())
157}
158
159fn nb_ns_double_in_line<'i>() -> Parser<'i> {
164 many0(Box::new(|state: State<'_>| {
165 let (ws_tokens, after_ws) = match many0(s_white())(state) {
166 Reply::Success { tokens, state } => (tokens, state),
167 other @ (Reply::Failure | Reply::Error(_)) => return other,
168 };
169 match ns_double_char()(after_ws) {
170 Reply::Success {
171 tokens: ns_tokens,
172 state: final_state,
173 } => {
174 let mut all = ws_tokens;
175 all.extend(ns_tokens);
176 Reply::Success {
177 tokens: all,
178 state: final_state,
179 }
180 }
181 Reply::Failure => Reply::Failure,
183 other @ Reply::Error(_) => other,
184 }
185 }))
186}
187
188fn s_double_escaped(n: i32) -> Parser<'static> {
192 Box::new(move |state| {
193 let (ws_tokens, after_ws) = match many0(s_white())(state) {
195 Reply::Success { tokens, state } => (tokens, state),
196 other @ (Reply::Failure | Reply::Error(_)) => return other,
197 };
198 let Some('\\') = after_ws.peek() else {
200 return Reply::Failure;
201 };
202 let backslash_pos = after_ws.pos;
203 let after_backslash = after_ws.advance('\\');
204 let backslash_token = crate::token::Token {
205 code: Code::Text,
206 pos: backslash_pos,
207 text: "\\",
208 };
209 let (break_tokens, after_break) = match b_non_content()(after_backslash) {
211 Reply::Success { tokens, state } => (tokens, state),
212 Reply::Failure => return Reply::Failure,
213 other @ Reply::Error(_) => return other,
214 };
215 let (empty_tokens, after_empty) = match many0(l_empty(n, Context::FlowIn))(after_break) {
217 Reply::Success { tokens, state } => (tokens, state),
218 other @ (Reply::Failure | Reply::Error(_)) => return other,
219 };
220 let (prefix_tokens, final_state) = match s_flow_line_prefix_ge(n)(after_empty) {
222 Reply::Success { tokens, state } => (tokens, state),
223 Reply::Failure => return Reply::Failure,
224 other @ Reply::Error(_) => return other,
225 };
226 let mut all = ws_tokens;
227 all.push(backslash_token);
228 all.extend(break_tokens);
229 all.extend(empty_tokens);
230 all.extend(prefix_tokens);
231 Reply::Success {
232 tokens: all,
233 state: final_state,
234 }
235 })
236}
237
238fn s_double_break(n: i32) -> Parser<'static> {
242 Box::new(move |state| match s_double_escaped(n)(state.clone()) {
244 reply @ Reply::Success { .. } => reply,
245 Reply::Failure | Reply::Error(_) => s_flow_folded(n)(state),
246 })
247}
248
249fn s_double_next_line(n: i32) -> Parser<'static> {
254 Box::new(move |state| {
255 let (break_tokens, after_break) = match s_double_break(n)(state) {
257 Reply::Success { tokens, state } => (tokens, state),
258 other @ (Reply::Failure | Reply::Error(_)) => return other,
259 };
260 let Some(ch) = after_break.peek() else {
263 return Reply::Success {
265 tokens: break_tokens,
266 state: after_break,
267 };
268 };
269 if matches!(ch, ' ' | '\t' | '"') {
271 return Reply::Success {
273 tokens: break_tokens,
274 state: after_break,
275 };
276 }
277 let (first_tokens, after_first) = match ns_double_char()(after_break.clone()) {
278 Reply::Success { tokens, state } => (tokens, state),
279 Reply::Failure | Reply::Error(_) => {
281 return Reply::Success {
282 tokens: break_tokens,
283 state: after_break,
284 };
285 }
286 };
287 let (inline_tokens, after_inline) = match nb_ns_double_in_line()(after_first) {
289 Reply::Success { tokens, state } => (tokens, state),
290 other @ (Reply::Failure | Reply::Error(_)) => return other,
291 };
292 let (tail_tokens, final_state) = match s_double_next_line(n)(after_inline.clone()) {
294 Reply::Success { tokens, state } => (tokens, state),
295 Reply::Failure | Reply::Error(_) => {
296 match many0(s_white())(after_inline.clone()) {
298 Reply::Success { tokens, state } => (tokens, state),
299 Reply::Failure | Reply::Error(_) => (Vec::new(), after_inline),
300 }
301 }
302 };
303 let mut all = break_tokens;
304 all.extend(first_tokens);
305 all.extend(inline_tokens);
306 all.extend(tail_tokens);
307 Reply::Success {
308 tokens: all,
309 state: final_state,
310 }
311 })
312}
313
314fn nb_double_multi_line(n: i32) -> Parser<'static> {
318 Box::new(move |state| {
319 let (inline_tokens, after_inline) = match nb_ns_double_in_line()(state) {
321 Reply::Success { tokens, state } => (tokens, state),
322 other @ (Reply::Failure | Reply::Error(_)) => return other,
323 };
324 let (tail_tokens, final_state) = match s_double_next_line(n)(after_inline.clone()) {
326 Reply::Success { tokens, state } => (tokens, state),
327 Reply::Failure | Reply::Error(_) => match many0(s_white())(after_inline.clone()) {
328 Reply::Success { tokens, state } => (tokens, state),
329 Reply::Failure | Reply::Error(_) => (Vec::new(), after_inline),
330 },
331 };
332 let mut all = inline_tokens;
333 all.extend(tail_tokens);
334 Reply::Success {
335 tokens: all,
336 state: final_state,
337 }
338 })
339}
340
341fn nb_double_text(n: i32, c: Context) -> Parser<'static> {
343 match c {
345 Context::FlowOut | Context::FlowIn => nb_double_multi_line(n),
346 Context::BlockKey | Context::FlowKey | Context::BlockOut | Context::BlockIn => {
347 nb_double_one_line()
348 }
349 }
350}
351
352#[must_use]
354pub fn c_double_quoted(n: i32, c: Context) -> Parser<'static> {
355 wrap_tokens(
356 Code::BeginScalar,
357 Code::EndScalar,
358 Box::new(move |state| {
359 let (open_tokens, after_open) = match token(Code::Indicator, char_parser('"'))(state) {
361 Reply::Success { tokens, state } => (tokens, state),
362 other @ (Reply::Failure | Reply::Error(_)) => return other,
363 };
364 let body_parser = nb_double_text(n, c);
366 match body_parser(after_open.clone()) {
367 Reply::Success {
368 tokens,
369 state: after_body,
370 } => {
371 match token(Code::Indicator, char_parser('"'))(after_body) {
373 Reply::Success {
374 tokens: close_tokens,
375 state: final_state,
376 } => {
377 let mut all = open_tokens;
378 all.extend(tokens);
379 all.extend(close_tokens);
380 Reply::Success {
381 tokens: all,
382 state: final_state,
383 }
384 }
385 Reply::Failure | Reply::Error(_) => Reply::Failure,
386 }
387 }
388 other @ (Reply::Failure | Reply::Error(_)) => other,
389 }
390 }),
391 )
392}
393
394#[must_use]
400pub fn c_quoted_quote<'i>() -> Parser<'i> {
401 seq(char_parser('\''), char_parser('\''))
402}
403
404#[must_use]
408pub fn nb_single_char<'i>() -> Parser<'i> {
409 Box::new(|state| {
410 let Some(ch) = state.peek() else {
411 return Reply::Failure;
412 };
413 if ch == '\'' {
414 return c_quoted_quote()(state);
416 }
417 if matches!(ch, '\n' | '\r') {
418 return Reply::Failure;
419 }
420 if ch == '\u{FEFF}' {
421 return Reply::Failure;
422 }
423 let start_pos = state.pos;
424 let start_input = state.input;
425 let new_state = state.advance(ch);
426 let byte_len = ch.len_utf8();
427 Reply::Success {
428 tokens: vec![Token {
429 code: Code::Text,
430 pos: start_pos,
431 text: &start_input[..byte_len],
432 }],
433 state: new_state,
434 }
435 })
436}
437
438#[must_use]
440pub fn ns_single_char<'i>() -> Parser<'i> {
441 Box::new(|state| {
442 let Some(ch) = state.peek() else {
443 return Reply::Failure;
444 };
445 if matches!(ch, ' ' | '\t') {
446 return Reply::Failure;
447 }
448 nb_single_char()(state)
449 })
450}
451
452fn nb_single_one_line<'i>() -> Parser<'i> {
454 many0(nb_single_char())
455}
456
457fn nb_ns_single_in_line<'i>() -> Parser<'i> {
462 many0(Box::new(|state: State<'_>| {
463 let (ws_tokens, after_ws) = match many0(s_white())(state) {
464 Reply::Success { tokens, state } => (tokens, state),
465 other @ (Reply::Failure | Reply::Error(_)) => return other,
466 };
467 match ns_single_char()(after_ws) {
468 Reply::Success {
469 tokens: ns_tokens,
470 state: final_state,
471 } => {
472 let mut all = ws_tokens;
473 all.extend(ns_tokens);
474 Reply::Success {
475 tokens: all,
476 state: final_state,
477 }
478 }
479 Reply::Failure => Reply::Failure,
480 other @ Reply::Error(_) => other,
481 }
482 }))
483}
484
485fn s_single_next_line(n: i32) -> Parser<'static> {
494 Box::new(move |state| {
495 let (fold_tokens, after_fold) = match s_flow_folded(n)(state) {
496 Reply::Success { tokens, state } => (tokens, state),
497 other @ (Reply::Failure | Reply::Error(_)) => return other,
498 };
499
500 let (first_tokens, after_first) = match ns_single_char()(after_fold.clone()) {
502 Reply::Success { tokens, state } => (tokens, state),
503 Reply::Failure | Reply::Error(_) => {
504 return Reply::Success {
505 tokens: fold_tokens,
506 state: after_fold,
507 };
508 }
509 };
510 let (inline_tokens, after_inline) = match nb_ns_single_in_line()(after_first) {
511 Reply::Success { tokens, state } => (tokens, state),
512 other @ (Reply::Failure | Reply::Error(_)) => return other,
513 };
514 let (tail_tokens, final_state) = match s_single_next_line(n)(after_inline.clone()) {
515 Reply::Success { tokens, state } => (tokens, state),
516 Reply::Failure | Reply::Error(_) => match many0(s_white())(after_inline.clone()) {
517 Reply::Success { tokens, state } => (tokens, state),
518 Reply::Failure | Reply::Error(_) => (Vec::new(), after_inline),
519 },
520 };
521 let mut all = fold_tokens;
522 all.extend(first_tokens);
523 all.extend(inline_tokens);
524 all.extend(tail_tokens);
525 Reply::Success {
526 tokens: all,
527 state: final_state,
528 }
529 })
530}
531
532fn nb_single_multi_line(n: i32) -> Parser<'static> {
536 Box::new(move |state| {
537 let (inline_tokens, after_inline) = match nb_ns_single_in_line()(state) {
538 Reply::Success { tokens, state } => (tokens, state),
539 other @ (Reply::Failure | Reply::Error(_)) => return other,
540 };
541 let (tail_tokens, final_state) = match s_single_next_line(n)(after_inline.clone()) {
542 Reply::Success { tokens, state } => (tokens, state),
543 Reply::Failure | Reply::Error(_) => match many0(s_white())(after_inline.clone()) {
544 Reply::Success { tokens, state } => (tokens, state),
545 Reply::Failure | Reply::Error(_) => (Vec::new(), after_inline),
546 },
547 };
548 let mut all = inline_tokens;
549 all.extend(tail_tokens);
550 Reply::Success {
551 tokens: all,
552 state: final_state,
553 }
554 })
555}
556
557fn nb_single_text(n: i32, c: Context) -> Parser<'static> {
559 match c {
561 Context::FlowOut | Context::FlowIn => nb_single_multi_line(n),
562 Context::BlockKey | Context::FlowKey | Context::BlockOut | Context::BlockIn => {
563 nb_single_one_line()
564 }
565 }
566}
567
568#[must_use]
570pub fn c_single_quoted(n: i32, c: Context) -> Parser<'static> {
571 wrap_tokens(
572 Code::BeginScalar,
573 Code::EndScalar,
574 Box::new(move |state| {
575 let (open_tokens, after_open) = match token(Code::Indicator, char_parser('\''))(state) {
576 Reply::Success { tokens, state } => (tokens, state),
577 other @ (Reply::Failure | Reply::Error(_)) => return other,
578 };
579 let body_parser = nb_single_text(n, c);
580 match body_parser(after_open.clone()) {
581 Reply::Success {
582 tokens: body_tokens,
583 state: after_body,
584 } => match token(Code::Indicator, char_parser('\''))(after_body) {
585 Reply::Success {
586 tokens: close_tokens,
587 state: final_state,
588 } => {
589 let mut all = open_tokens;
590 all.extend(body_tokens);
591 all.extend(close_tokens);
592 Reply::Success {
593 tokens: all,
594 state: final_state,
595 }
596 }
597 Reply::Failure | Reply::Error(_) => Reply::Failure,
598 },
599 other @ (Reply::Failure | Reply::Error(_)) => other,
600 }
601 }),
602 )
603}
604
605fn nb_ns_plain_in_line(c: Context) -> Parser<'static> {
615 use crate::chars::s_white;
616 many0(Box::new(move |state: State<'_>| {
617 let before_ws = state.pos.byte_offset;
618 let (ws_tokens, after_ws) = match many0(s_white())(state) {
619 Reply::Success { tokens, state } => (tokens, state),
620 Reply::Failure | Reply::Error(_) => unreachable!("many0 always succeeds"),
621 };
622 let had_ws = after_ws.pos.byte_offset > before_ws;
623 if had_ws && after_ws.peek() == Some('#') {
625 return Reply::Failure;
626 }
627 match ns_plain_char(c)(after_ws) {
628 Reply::Success {
629 tokens: char_tokens,
630 state: final_state,
631 } => {
632 let mut all = ws_tokens;
633 all.extend(char_tokens);
634 Reply::Success {
635 tokens: all,
636 state: final_state,
637 }
638 }
639 other @ (Reply::Failure | Reply::Error(_)) => other,
640 }
641 }))
642}
643
644fn ns_plain_one_line(c: Context) -> Parser<'static> {
646 seq(ns_plain_first(c), nb_ns_plain_in_line(c))
647}
648
649fn s_ns_plain_next_line(n: i32, c: Context) -> Parser<'static> {
654 Box::new(move |state| {
655 let (fold_tokens, after_fold) = match s_flow_folded(n)(state) {
656 Reply::Success { tokens, state } => (tokens, state),
657 other @ (Reply::Failure | Reply::Error(_)) => return other,
658 };
659 if after_fold.peek() == Some('#') {
661 return Reply::Failure;
662 }
663 let rest = seq(
664 neg_lookahead(c_forbidden()),
665 seq(ns_plain_char(c), nb_ns_plain_in_line(c)),
666 );
667 match rest(after_fold) {
668 Reply::Success {
669 tokens: rest_tokens,
670 state: final_state,
671 } => {
672 let mut all = fold_tokens;
673 all.extend(rest_tokens);
674 Reply::Success {
675 tokens: all,
676 state: final_state,
677 }
678 }
679 other @ (Reply::Failure | Reply::Error(_)) => other,
680 }
681 })
682}
683
684fn ns_plain_multi_line(n: i32, c: Context) -> Parser<'static> {
686 seq(ns_plain_one_line(c), many0(s_ns_plain_next_line(n, c)))
687}
688
689#[must_use]
696pub fn ns_plain(n: i32, c: Context) -> Parser<'static> {
697 let inner: Parser<'static> = match c {
698 Context::BlockKey | Context::FlowKey => token(Code::Text, ns_plain_one_line(c)),
699 Context::BlockOut | Context::BlockIn | Context::FlowOut | Context::FlowIn => {
700 token(Code::Text, ns_plain_multi_line(n, c))
701 }
702 };
703 wrap_tokens(Code::BeginScalar, Code::EndScalar, inner)
704}
705
706#[must_use]
714pub fn c_flow_sequence(n: i32, c: Context) -> Parser<'static> {
715 wrap_tokens(
716 Code::BeginSequence,
717 Code::EndSequence,
718 Box::new(move |state| {
719 let outer_c = state.c;
720 let (open_tokens, after_open) = match token(Code::Indicator, char_parser('['))(state) {
722 Reply::Success { tokens, state } => (tokens, state),
723 other @ (Reply::Failure | Reply::Error(_)) => return other,
724 };
725 let after_sep = skip_flow_sep(n, after_open);
727 let inner_c = inner_flow_context(c);
728 let inner_state = State {
729 c: inner_c,
730 ..after_sep
731 };
732 let (entries_tokens, after_entries) =
734 match ns_s_flow_seq_entries(n, inner_c)(inner_state.clone()) {
735 Reply::Success { tokens, state } => (tokens, state),
736 Reply::Failure | Reply::Error(_) => (Vec::new(), inner_state),
737 };
738 let after_sep2 = skip_flow_sep(n, after_entries);
740 match token(Code::Indicator, char_parser(']'))(after_sep2) {
742 Reply::Success {
743 tokens: close_tokens,
744 state: final_state,
745 } => {
746 let mut all = open_tokens;
747 all.extend(entries_tokens);
748 all.extend(close_tokens);
749 Reply::Success {
750 tokens: all,
751 state: State {
752 c: outer_c,
753 ..final_state
754 },
755 }
756 }
757 Reply::Failure | Reply::Error(_) => Reply::Failure,
758 }
759 }),
760 )
761}
762
763fn ns_s_flow_seq_entries(n: i32, c: Context) -> Parser<'static> {
768 Box::new(move |state| {
769 let (first_tokens, after_first) = match ns_flow_seq_entry(n, c)(state) {
771 Reply::Success { tokens, state } => (tokens, state),
772 Reply::Error(e) => return Reply::Error(e),
773 Reply::Failure => return Reply::Failure,
774 };
775 let mut all_tokens = first_tokens;
777 let mut current = after_first;
778 loop {
779 let after_sep = skip_flow_sep(n, current.clone());
780 match token(Code::Indicator, char_parser(','))(after_sep) {
781 Reply::Error(e) => return Reply::Error(e),
782 Reply::Failure => break,
783 Reply::Success {
784 tokens: comma_tokens,
785 state: after_comma,
786 } => {
787 let after_sep2 = skip_flow_sep(n, after_comma.clone());
788 let (entry_tokens, after_entry) =
789 match ns_flow_seq_entry(n, c)(after_sep2.clone()) {
790 Reply::Success { tokens, state } => (tokens, state),
791 Reply::Failure | Reply::Error(_) => {
792 if after_sep2.peek() == Some(',') {
794 return Reply::Failure;
795 }
796 (Vec::new(), after_sep2)
797 }
798 };
799 all_tokens.extend(comma_tokens);
800 all_tokens.extend(entry_tokens);
801 current = after_entry;
802 }
803 }
804 }
805 Reply::Success {
806 tokens: all_tokens,
807 state: current,
808 }
809 })
810}
811
812fn ns_flow_seq_entry(n: i32, c: Context) -> Parser<'static> {
819 Box::new(move |state| {
820 let pair = c_ns_flow_pair(n, c)(state.clone());
821 match &pair {
822 Reply::Success {
823 state: pair_state, ..
824 } => {
825 let next = pair_state.peek();
828 let looks_complete = matches!(next, None | Some(',' | ']' | '}' | ' ' | '\t'));
829 if looks_complete {
830 return pair;
831 }
832 let node = ns_flow_node(n, c)(state);
834 let node_end = match &node {
835 Reply::Success { state, .. } => state.pos.byte_offset,
836 Reply::Failure | Reply::Error(_) => 0,
837 };
838 if node_end > pair_state.pos.byte_offset {
839 node
840 } else {
841 pair
842 }
843 }
844 Reply::Failure | Reply::Error(_) => ns_flow_node(n, c)(state),
845 }
846 })
847}
848
849#[must_use]
857pub fn c_flow_mapping(n: i32, c: Context) -> Parser<'static> {
858 wrap_tokens(
859 Code::BeginMapping,
860 Code::EndMapping,
861 Box::new(move |state| {
862 let outer_c = state.c;
863 let (open_tokens, after_open) = match token(Code::Indicator, char_parser('{'))(state) {
865 Reply::Success { tokens, state } => (tokens, state),
866 other @ (Reply::Failure | Reply::Error(_)) => return other,
867 };
868 let after_sep = skip_flow_sep(n, after_open);
869 let inner_c = inner_flow_context(c);
870 let inner_state = State {
871 c: inner_c,
872 ..after_sep
873 };
874 let (entries_tokens, after_entries) =
875 match ns_s_flow_map_entries(n, inner_c)(inner_state) {
876 Reply::Success { tokens, state } => (tokens, state),
877 Reply::Failure => return Reply::Failure,
878 Reply::Error(e) => return Reply::Error(e),
879 };
880 let after_sep2 = skip_flow_sep(n, after_entries);
881 match token(Code::Indicator, char_parser('}'))(after_sep2) {
883 Reply::Success {
884 tokens: close_tokens,
885 state: final_state,
886 } => {
887 let mut all = open_tokens;
888 all.extend(entries_tokens);
889 all.extend(close_tokens);
890 Reply::Success {
891 tokens: all,
892 state: State {
893 c: outer_c,
894 ..final_state
895 },
896 }
897 }
898 Reply::Failure | Reply::Error(_) => Reply::Failure,
899 }
900 }),
901 )
902}
903
904fn ns_s_flow_map_entries(n: i32, c: Context) -> Parser<'static> {
906 Box::new(move |state| {
907 let (first_tokens, after_first) = match ns_flow_map_entry(n, c)(state.clone()) {
908 Reply::Success { tokens, state } => (tokens, state),
909 Reply::Error(e) => return Reply::Error(e),
910 Reply::Failure => {
911 return Reply::Success {
912 tokens: Vec::new(),
913 state,
914 };
915 }
916 };
917 let mut all_tokens = first_tokens;
918 let mut current = after_first;
919 loop {
920 let after_sep = skip_flow_sep(n, current.clone());
921 match token(Code::Indicator, char_parser(','))(after_sep) {
922 Reply::Error(e) => return Reply::Error(e),
923 Reply::Failure => break,
924 Reply::Success {
925 tokens: comma_tokens,
926 state: after_comma,
927 } => {
928 let after_sep2 = skip_flow_sep(n, after_comma);
929 let (entry_tokens, after_entry) =
930 match ns_flow_map_entry(n, c)(after_sep2.clone()) {
931 Reply::Success { tokens, state } => (tokens, state),
932 Reply::Failure | Reply::Error(_) => (Vec::new(), after_sep2),
933 };
934 all_tokens.extend(comma_tokens);
935 all_tokens.extend(entry_tokens);
936 current = after_entry;
937 }
938 }
939 }
940 Reply::Success {
941 tokens: all_tokens,
942 state: current,
943 }
944 })
945}
946
947fn ns_flow_map_entry(n: i32, c: Context) -> Parser<'static> {
949 Box::new(move |state| {
950 let explicit = ns_flow_map_explicit_entry(n, c)(state.clone());
951 match explicit {
952 Reply::Success { .. } | Reply::Error(_) => explicit,
953 Reply::Failure => ns_flow_map_implicit_entry(n, c)(state),
954 }
955 })
956}
957
958fn ns_flow_map_explicit_entry(n: i32, c: Context) -> Parser<'static> {
960 wrap_tokens(
961 Code::BeginPair,
962 Code::EndPair,
963 Box::new(move |state| {
964 let (q_tokens, after_q) = match token(Code::Indicator, char_parser('?'))(state) {
965 Reply::Success { tokens, state } => (tokens, state),
966 other @ (Reply::Failure | Reply::Error(_)) => return other,
967 };
968 let after_sep = skip_flow_sep(n, after_q);
969 let (key_tokens, after_key) = match ns_flow_yaml_node(n, c)(after_sep.clone()) {
971 Reply::Success { tokens, state } => (tokens, state),
972 Reply::Failure | Reply::Error(_) => (Vec::new(), after_sep),
973 };
974 let (value_tokens, final_state) = match c_ns_flow_map_value(n, c)(after_key.clone()) {
976 Reply::Success { tokens, state } => (tokens, state),
977 Reply::Failure | Reply::Error(_) => (Vec::new(), after_key),
978 };
979 let mut all = q_tokens;
980 all.extend(key_tokens);
981 all.extend(value_tokens);
982 Reply::Success {
983 tokens: all,
984 state: final_state,
985 }
986 }),
987 )
988}
989
990fn ns_flow_map_implicit_entry(n: i32, c: Context) -> Parser<'static> {
992 Box::new(move |state| {
993 let yaml = ns_flow_map_yaml_key_entry(n, c)(state.clone());
994 match yaml {
995 Reply::Success { .. } | Reply::Error(_) => return yaml,
996 Reply::Failure => {}
997 }
998 let json = c_ns_flow_map_json_key_entry(n, c)(state.clone());
999 match json {
1000 Reply::Success { .. } | Reply::Error(_) => return json,
1001 Reply::Failure => {}
1002 }
1003 c_ns_flow_map_empty_key_entry(n, c)(state)
1004 })
1005}
1006
1007fn c_ns_flow_map_json_key_entry(n: i32, c: Context) -> Parser<'static> {
1012 wrap_tokens(
1013 Code::BeginPair,
1014 Code::EndPair,
1015 Box::new(move |state| {
1016 let (key_tokens, after_key) = match c_flow_json_node(n, c)(state.clone()) {
1018 Reply::Success { tokens, state } => (tokens, state),
1019 other @ (Reply::Failure | Reply::Error(_)) => return other,
1020 };
1021 let after_sep = skip_flow_sep(n, after_key.clone());
1025 let (value_tokens, final_state) =
1026 match c_ns_flow_map_adjacent_value(n, c)(after_sep.clone()) {
1027 Reply::Success { tokens, state } => (tokens, state),
1028 Reply::Failure | Reply::Error(_) => {
1029 match c_ns_flow_map_separate_value(n, c)(after_sep.clone()) {
1030 Reply::Success { tokens, state } => (tokens, state),
1031 Reply::Failure | Reply::Error(_) => (Vec::new(), after_key),
1032 }
1033 }
1034 };
1035 let mut all = key_tokens;
1036 all.extend(value_tokens);
1037 Reply::Success {
1038 tokens: all,
1039 state: final_state,
1040 }
1041 }),
1042 )
1043}
1044
1045fn ns_flow_map_yaml_key_entry(n: i32, c: Context) -> Parser<'static> {
1050 wrap_tokens(
1051 Code::BeginPair,
1052 Code::EndPair,
1053 Box::new(move |state| {
1054 let (key_tokens, after_key) = match ns_flow_yaml_node(n, c)(state.clone()) {
1056 Reply::Success { tokens, state } => (tokens, state),
1057 other @ (Reply::Failure | Reply::Error(_)) => return other,
1058 };
1059 let after_sep = skip_flow_sep(n, after_key.clone());
1061 let (value_tokens, final_state) =
1062 match c_ns_flow_map_separate_value(n, c)(after_sep.clone()) {
1063 Reply::Success { tokens, state } => (tokens, state),
1064 Reply::Failure | Reply::Error(_) => {
1065 match c_ns_flow_map_adjacent_value(n, c)(after_key.clone()) {
1066 Reply::Success { tokens, state } => (tokens, state),
1067 Reply::Failure | Reply::Error(_) => (Vec::new(), after_key),
1068 }
1069 }
1070 };
1071 let mut all = key_tokens;
1072 all.extend(value_tokens);
1073 Reply::Success {
1074 tokens: all,
1075 state: final_state,
1076 }
1077 }),
1078 )
1079}
1080
1081fn c_ns_flow_map_empty_key_entry(n: i32, c: Context) -> Parser<'static> {
1083 wrap_tokens(
1084 Code::BeginPair,
1085 Code::EndPair,
1086 Box::new(move |state| {
1087 let Some(':') = state.peek() else {
1089 return Reply::Failure;
1090 };
1091 let colon_input = state.input;
1092 let colon_pos = state.pos;
1093 let after_colon = state.advance(':');
1094 let colon_token = Token {
1095 code: Code::Indicator,
1096 pos: colon_pos,
1097 text: &colon_input[..1],
1098 };
1099 let after_sep = skip_flow_sep(n, after_colon.clone());
1100 let (value_tokens, final_state) = match ns_flow_node(n, c)(after_sep.clone()) {
1101 Reply::Success { tokens, state } => (tokens, state),
1102 Reply::Failure | Reply::Error(_) => (Vec::new(), after_colon),
1103 };
1104 let mut all = vec![colon_token];
1105 all.extend(value_tokens);
1106 Reply::Success {
1107 tokens: all,
1108 state: final_state,
1109 }
1110 }),
1111 )
1112}
1113
1114fn c_ns_flow_map_separate_value(n: i32, c: Context) -> Parser<'static> {
1119 Box::new(move |state| {
1120 let Some(':') = state.peek() else {
1121 return Reply::Failure;
1122 };
1123 let colon_input = state.input;
1124 let colon_pos = state.pos;
1125 let after_colon = state.advance(':');
1126 match after_colon.peek() {
1128 None => {
1129 Reply::Success {
1131 tokens: vec![Token {
1132 code: Code::Indicator,
1133 pos: colon_pos,
1134 text: &colon_input[..1],
1135 }],
1136 state: after_colon,
1137 }
1138 }
1139 Some(',' | '}' | ']') => {
1140 Reply::Success {
1142 tokens: vec![Token {
1143 code: Code::Indicator,
1144 pos: colon_pos,
1145 text: &colon_input[..1],
1146 }],
1147 state: after_colon,
1148 }
1149 }
1150 Some(nc) if !matches!(nc, ' ' | '\t' | '\n' | '\r') => {
1151 Reply::Failure
1153 }
1154 _ => {
1155 let colon_token = Token {
1156 code: Code::Indicator,
1157 pos: colon_pos,
1158 text: &colon_input[..1],
1159 };
1160 let after_sep = skip_flow_sep(n, after_colon.clone());
1161 let (value_tokens, final_state) = match ns_flow_node(n, c)(after_sep.clone()) {
1162 Reply::Success { tokens, state } => (tokens, state),
1163 Reply::Failure | Reply::Error(_) => (Vec::new(), after_colon),
1164 };
1165 let mut all = vec![colon_token];
1166 all.extend(value_tokens);
1167 Reply::Success {
1168 tokens: all,
1169 state: final_state,
1170 }
1171 }
1172 }
1173 })
1174}
1175
1176fn c_ns_flow_map_adjacent_value(n: i32, c: Context) -> Parser<'static> {
1178 Box::new(move |state| {
1179 let Some(':') = state.peek() else {
1180 return Reply::Failure;
1181 };
1182 let colon_input = state.input;
1183 let colon_pos = state.pos;
1184 let after_colon = state.advance(':');
1185 let colon_token = Token {
1186 code: Code::Indicator,
1187 pos: colon_pos,
1188 text: &colon_input[..1],
1189 };
1190 let after_sep = skip_flow_sep(n, after_colon.clone());
1192 let (value_tokens, final_state) = match ns_flow_node(n, c)(after_sep.clone()) {
1193 Reply::Success { tokens, state } => (tokens, state),
1194 Reply::Failure | Reply::Error(_) => (Vec::new(), after_colon),
1195 };
1196 let mut all = vec![colon_token];
1197 all.extend(value_tokens);
1198 Reply::Success {
1199 tokens: all,
1200 state: final_state,
1201 }
1202 })
1203}
1204
1205fn c_ns_flow_map_value(n: i32, c: Context) -> Parser<'static> {
1207 Box::new(move |state| {
1208 let after_sep = skip_flow_sep(n, state);
1209 c_ns_flow_map_separate_value(n, c)(after_sep)
1210 })
1211}
1212
1213fn ns_flow_yaml_content(n: i32, c: Context) -> Parser<'static> {
1219 ns_plain(n, c)
1220}
1221
1222fn c_flow_json_content(n: i32, c: Context) -> Parser<'static> {
1224 Box::new(move |state| {
1225 let dq = c_double_quoted(n, c)(state.clone());
1226 if matches!(dq, Reply::Success { .. } | Reply::Error(_)) {
1227 return dq;
1228 }
1229 let sq = c_single_quoted(n, c)(state.clone());
1230 if matches!(sq, Reply::Success { .. } | Reply::Error(_)) {
1231 return sq;
1232 }
1233 let seq_ = c_flow_sequence(n, c)(state.clone());
1234 if matches!(seq_, Reply::Success { .. } | Reply::Error(_)) {
1235 return seq_;
1236 }
1237 c_flow_mapping(n, c)(state)
1238 })
1239}
1240
1241fn ns_flow_content(n: i32, c: Context) -> Parser<'static> {
1243 Box::new(move |state| {
1244 let yaml = ns_flow_yaml_content(n, c)(state.clone());
1245 match yaml {
1246 Reply::Success { .. } | Reply::Error(_) => yaml,
1247 Reply::Failure => c_flow_json_content(n, c)(state),
1248 }
1249 })
1250}
1251
1252#[must_use]
1254pub fn ns_flow_yaml_node(n: i32, c: Context) -> Parser<'static> {
1255 Box::new(move |state| {
1256 let alias = c_ns_alias_node()(state.clone());
1258 if let Reply::Success { .. } = alias {
1259 return alias;
1260 }
1261 match c_ns_properties(n, c)(state.clone()) {
1263 Reply::Success {
1264 tokens: props_tokens,
1265 state: after_props,
1266 } => {
1267 let content_state = match s_separate(n, c)(after_props.clone()) {
1269 Reply::Success { state, .. } => state,
1270 Reply::Failure | Reply::Error(_) => after_props.clone(),
1271 };
1272 let (content_tokens, final_state) =
1273 match ns_flow_content(n, c)(content_state.clone()) {
1274 Reply::Success { tokens, state } => (tokens, state),
1275 Reply::Failure | Reply::Error(_) => (Vec::new(), after_props),
1276 };
1277 let mut all = props_tokens;
1278 all.extend(content_tokens);
1279 Reply::Success {
1280 tokens: all,
1281 state: final_state,
1282 }
1283 }
1284 Reply::Failure | Reply::Error(_) => ns_flow_yaml_content(n, c)(state),
1285 }
1286 })
1287}
1288
1289#[must_use]
1291pub fn c_flow_json_node(n: i32, c: Context) -> Parser<'static> {
1292 Box::new(move |state| {
1293 let (props_tokens, content_state) = match c_ns_properties(n, c)(state.clone()) {
1295 Reply::Success {
1296 tokens,
1297 state: after_props,
1298 } => {
1299 let sep_state = match s_separate(n, c)(after_props.clone()) {
1300 Reply::Success { state, .. } => state,
1301 Reply::Failure | Reply::Error(_) => after_props,
1302 };
1303 (tokens, sep_state)
1304 }
1305 Reply::Failure | Reply::Error(_) => (Vec::new(), state),
1306 };
1307 match c_flow_json_content(n, c)(content_state) {
1308 Reply::Success {
1309 tokens: content_tokens,
1310 state: final_state,
1311 } => {
1312 let mut all = props_tokens;
1313 all.extend(content_tokens);
1314 Reply::Success {
1315 tokens: all,
1316 state: final_state,
1317 }
1318 }
1319 other @ (Reply::Failure | Reply::Error(_)) => other,
1320 }
1321 })
1322}
1323
1324#[must_use]
1326pub fn ns_flow_node(n: i32, c: Context) -> Parser<'static> {
1327 Box::new(move |state| {
1328 let yaml = ns_flow_yaml_node(n, c)(state.clone());
1329 match yaml {
1330 Reply::Success { .. } | Reply::Error(_) => yaml,
1331 Reply::Failure => c_flow_json_node(n, c)(state),
1332 }
1333 })
1334}
1335
1336#[must_use]
1340pub fn c_ns_flow_pair(n: i32, c: Context) -> Parser<'static> {
1341 Box::new(move |state| {
1342 let explicit = ns_flow_map_explicit_entry(n, c)(state.clone());
1343 match explicit {
1344 Reply::Success { .. } | Reply::Error(_) => return explicit,
1345 Reply::Failure => {}
1346 }
1347 let yaml_key = wrap_tokens(
1352 Code::BeginPair,
1353 Code::EndPair,
1354 Box::new(move |s: State<'static>| {
1355 let (key_tokens, after_key) =
1356 match ns_flow_yaml_node(n, Context::FlowKey)(s.clone()) {
1357 Reply::Success { tokens, state } => (tokens, state),
1358 Reply::Failure | Reply::Error(_) => return Reply::Failure,
1359 };
1360 let after_sep = match crate::structure::s_separate_in_line()(after_key.clone()) {
1362 Reply::Success { state, .. } => state,
1363 Reply::Failure | Reply::Error(_) => after_key.clone(),
1364 };
1365 let (value_tokens, final_state) =
1366 match c_ns_flow_map_separate_value(n, c)(after_sep.clone()) {
1367 Reply::Success { tokens, state } => (tokens, state),
1368 Reply::Failure | Reply::Error(_) => {
1369 match c_ns_flow_map_adjacent_value(n, c)(after_sep.clone()) {
1370 Reply::Success { tokens, state } => (tokens, state),
1371 Reply::Failure | Reply::Error(_) => (Vec::new(), after_key),
1372 }
1373 }
1374 };
1375 let mut all = key_tokens;
1376 all.extend(value_tokens);
1377 Reply::Success {
1378 tokens: all,
1379 state: final_state,
1380 }
1381 }),
1382 )(state.clone());
1383 match yaml_key {
1384 Reply::Success { .. } | Reply::Error(_) => return yaml_key,
1385 Reply::Failure => {}
1386 }
1387 let json = c_ns_flow_map_json_key_entry(n, c)(state.clone());
1389 match json {
1390 Reply::Success { .. } | Reply::Error(_) => return json,
1391 Reply::Failure => {}
1392 }
1393 c_ns_flow_map_empty_key_entry(n, c)(state)
1394 })
1395}
1396
1397fn skip_flow_sep(n: i32, state: State<'static>) -> State<'static> {
1407 match s_separate_ge(n, state.c)(state.clone()) {
1408 Reply::Success { state, .. } => state,
1409 Reply::Failure | Reply::Error(_) => state,
1410 }
1411}
1412
1413const fn inner_flow_context(c: Context) -> Context {
1415 match c {
1416 Context::FlowOut | Context::FlowIn | Context::BlockOut | Context::BlockIn => {
1417 Context::FlowIn
1418 }
1419 Context::BlockKey | Context::FlowKey => Context::FlowKey,
1420 }
1421}
1422
1423#[cfg(test)]
1428#[allow(
1429 clippy::indexing_slicing,
1430 clippy::expect_used,
1431 clippy::unwrap_used,
1432 unused_imports
1433)]
1434mod tests {
1435 use super::*;
1436 use crate::combinator::{Reply, State};
1437 use crate::token::Code;
1438
1439 fn state(input: &str) -> State<'_> {
1440 State::new(input)
1441 }
1442
1443 fn is_success(reply: &Reply<'_>) -> bool {
1444 matches!(reply, Reply::Success { .. })
1445 }
1446
1447 fn is_failure(reply: &Reply<'_>) -> bool {
1448 matches!(reply, Reply::Failure)
1449 }
1450
1451 fn remaining<'a>(reply: &'a Reply<'a>) -> &'a str {
1452 match reply {
1453 Reply::Success { state, .. } => state.input,
1454 Reply::Failure | Reply::Error(_) => panic!("expected success"),
1455 }
1456 }
1457
1458 fn codes(reply: Reply<'_>) -> Vec<Code> {
1459 match reply {
1460 Reply::Success { tokens, .. } => tokens.into_iter().map(|t| t.code).collect(),
1461 Reply::Failure | Reply::Error(_) => panic!("expected success"),
1462 }
1463 }
1464
1465 #[test]
1470 fn c_ns_alias_node_emits_begin_alias() {
1471 let c = codes(c_ns_alias_node()(state("*myanchor rest")));
1472 assert_eq!(c.first().copied(), Some(Code::BeginAlias));
1473 }
1474
1475 #[test]
1476 fn c_ns_alias_node_emits_end_alias() {
1477 let c = codes(c_ns_alias_node()(state("*myanchor rest")));
1478 assert_eq!(c.last().copied(), Some(Code::EndAlias));
1479 }
1480
1481 #[test]
1482 fn c_ns_alias_node_emits_indicator_for_asterisk() {
1483 let c = codes(c_ns_alias_node()(state("*myanchor rest")));
1484 assert!(c.contains(&Code::Indicator));
1485 }
1486
1487 #[test]
1488 fn c_ns_alias_node_emits_meta_for_name() {
1489 let c = codes(c_ns_alias_node()(state("*myanchor rest")));
1490 assert!(c.contains(&Code::Meta));
1491 }
1492
1493 #[test]
1494 fn c_ns_alias_node_stops_before_space() {
1495 let reply = c_ns_alias_node()(state("*myanchor rest"));
1496 assert_eq!(remaining(&reply), " rest");
1497 }
1498
1499 #[test]
1500 fn c_ns_alias_node_stops_at_flow_indicator() {
1501 let reply = c_ns_alias_node()(state("*name]rest"));
1502 assert!(is_success(&reply));
1503 assert_eq!(remaining(&reply), "]rest");
1504 }
1505
1506 #[test]
1507 fn c_ns_alias_node_fails_without_asterisk() {
1508 let reply = c_ns_alias_node()(state("myanchor"));
1509 assert!(is_failure(&reply));
1510 }
1511
1512 #[test]
1513 fn c_ns_alias_node_fails_with_empty_name() {
1514 let reply = c_ns_alias_node()(state("* rest"));
1515 assert!(is_failure(&reply));
1516 }
1517
1518 #[test]
1523 fn e_scalar_succeeds_with_zero_consumption() {
1524 let reply = e_scalar()(state("rest"));
1525 assert!(is_success(&reply));
1526 assert_eq!(remaining(&reply), "rest");
1527 }
1528
1529 #[test]
1530 fn e_scalar_succeeds_on_empty_input() {
1531 let reply = e_scalar()(state(""));
1532 assert!(is_success(&reply));
1533 }
1534
1535 #[test]
1536 fn e_node_succeeds_with_zero_consumption() {
1537 let reply = e_node()(state("rest"));
1538 assert!(is_success(&reply));
1539 assert_eq!(remaining(&reply), "rest");
1540 }
1541
1542 #[test]
1543 fn e_node_succeeds_on_empty_input() {
1544 let reply = e_node()(state(""));
1545 assert!(is_success(&reply));
1546 }
1547
1548 #[test]
1553 fn c_double_quoted_emits_begin_scalar() {
1554 let c = codes(c_double_quoted(0, Context::FlowOut)(state(
1555 "\"hello\" rest",
1556 )));
1557 assert_eq!(c.first().copied(), Some(Code::BeginScalar));
1558 }
1559
1560 #[test]
1561 fn c_double_quoted_emits_end_scalar() {
1562 let c = codes(c_double_quoted(0, Context::FlowOut)(state(
1563 "\"hello\" rest",
1564 )));
1565 assert_eq!(c.last().copied(), Some(Code::EndScalar));
1566 }
1567
1568 #[test]
1569 fn c_double_quoted_emits_text_for_content() {
1570 let c = codes(c_double_quoted(0, Context::FlowOut)(state(
1571 "\"hello\" rest",
1572 )));
1573 assert!(c.contains(&Code::Text));
1574 }
1575
1576 #[test]
1577 fn c_double_quoted_consumes_through_closing_quote() {
1578 let reply = c_double_quoted(0, Context::FlowOut)(state("\"hello\" rest"));
1579 assert_eq!(remaining(&reply), " rest");
1580 }
1581
1582 #[test]
1583 fn c_double_quoted_accepts_empty_string() {
1584 let reply = c_double_quoted(0, Context::FlowOut)(state("\"\" rest"));
1585 assert!(is_success(&reply));
1586 let c = codes(c_double_quoted(0, Context::FlowOut)(state("\"\" rest")));
1587 assert!(c.contains(&Code::BeginScalar));
1588 assert!(c.contains(&Code::EndScalar));
1589 }
1590
1591 #[test]
1592 fn c_double_quoted_fails_without_opening_quote() {
1593 let reply = c_double_quoted(0, Context::FlowOut)(state("hello\""));
1594 assert!(is_failure(&reply));
1595 }
1596
1597 #[test]
1598 fn c_double_quoted_fails_without_closing_quote() {
1599 let reply = c_double_quoted(0, Context::FlowOut)(state("\"hello"));
1600 assert!(is_failure(&reply));
1601 }
1602
1603 #[test]
1604 fn c_double_quoted_handles_escape_newline() {
1605 let reply = c_double_quoted(0, Context::FlowOut)(state("\"hello\\nworld\""));
1606 assert!(is_success(&reply));
1607 let c = codes(c_double_quoted(0, Context::FlowOut)(state(
1609 "\"hello\\nworld\"",
1610 )));
1611 assert!(c.contains(&Code::Text));
1612 }
1613
1614 #[test]
1615 fn c_double_quoted_handles_escape_tab() {
1616 let reply = c_double_quoted(0, Context::FlowOut)(state("\"\\t\""));
1617 assert!(is_success(&reply));
1618 let c = codes(c_double_quoted(0, Context::FlowOut)(state("\"\\t\"")));
1619 assert!(c.contains(&Code::Text));
1621 }
1622
1623 #[test]
1624 fn c_double_quoted_handles_escape_backslash() {
1625 let reply = c_double_quoted(0, Context::FlowOut)(state("\"\\\\ \""));
1626 assert!(is_success(&reply));
1627 let c = codes(c_double_quoted(0, Context::FlowOut)(state("\"\\\\ \"")));
1628 assert!(c.contains(&Code::Text));
1629 }
1630
1631 #[test]
1632 fn c_double_quoted_handles_escape_double_quote() {
1633 let reply = c_double_quoted(0, Context::FlowOut)(state("\"\\\"\""));
1634 assert!(is_success(&reply));
1635 }
1636
1637 #[test]
1638 fn c_double_quoted_handles_unicode_escape() {
1639 let reply = c_double_quoted(0, Context::FlowOut)(state("\"\\u0041\""));
1640 assert!(is_success(&reply));
1641 let c = codes(c_double_quoted(0, Context::FlowOut)(state("\"\\u0041\"")));
1642 assert!(c.contains(&Code::Text));
1643 }
1644
1645 #[test]
1646 fn c_double_quoted_rejects_invalid_escape() {
1647 let reply = c_double_quoted(0, Context::FlowOut)(state("\"\\z\""));
1648 assert!(is_failure(&reply));
1649 }
1650
1651 #[test]
1652 fn c_double_quoted_accepts_multiline() {
1653 let reply = c_double_quoted(0, Context::FlowOut)(state("\"line1\nline2\""));
1654 assert!(is_success(&reply));
1655 assert_eq!(remaining(&reply), "");
1656 }
1657
1658 #[test]
1659 fn nb_double_char_accepts_regular_char() {
1660 let reply = nb_double_char()(state("a"));
1661 assert!(is_success(&reply));
1662 }
1663
1664 #[test]
1665 fn nb_double_char_accepts_escape_sequence() {
1666 let reply = nb_double_char()(state("\\n"));
1667 assert!(is_success(&reply));
1668 let c = codes(nb_double_char()(state("\\n")));
1670 assert!(c.contains(&Code::Text));
1671 }
1672
1673 #[test]
1674 fn nb_double_char_fails_on_bare_double_quote() {
1675 let reply = nb_double_char()(state("\""));
1676 assert!(is_failure(&reply));
1677 }
1678
1679 #[test]
1680 fn ns_double_char_fails_on_space() {
1681 let reply = ns_double_char()(state(" a"));
1682 assert!(is_failure(&reply));
1683 }
1684
1685 #[test]
1686 fn ns_double_char_accepts_regular_non_space_char() {
1687 let reply = ns_double_char()(state("a"));
1688 assert!(is_success(&reply));
1689 }
1690
1691 #[test]
1692 fn nb_double_char_fails_on_backslash_alone() {
1693 let reply = nb_double_char()(state("\\"));
1694 assert!(is_failure(&reply));
1695 }
1696
1697 #[test]
1698 fn c_double_quoted_handles_folded_line() {
1699 let reply = c_double_quoted(0, Context::FlowOut)(state("\"word1\n word2\""));
1700 assert!(is_success(&reply));
1701 }
1702
1703 #[test]
1704 fn c_double_quoted_handles_trimmed_blank_lines() {
1705 let reply = c_double_quoted(0, Context::FlowOut)(state("\"word1\n\n word2\""));
1706 assert!(is_success(&reply));
1707 }
1708
1709 #[test]
1714 fn c_single_quoted_emits_begin_scalar() {
1715 let c = codes(c_single_quoted(0, Context::FlowOut)(state("'hello' rest")));
1716 assert_eq!(c.first().copied(), Some(Code::BeginScalar));
1717 }
1718
1719 #[test]
1720 fn c_single_quoted_emits_end_scalar() {
1721 let c = codes(c_single_quoted(0, Context::FlowOut)(state("'hello' rest")));
1722 assert_eq!(c.last().copied(), Some(Code::EndScalar));
1723 }
1724
1725 #[test]
1726 fn c_single_quoted_emits_text_for_content() {
1727 let c = codes(c_single_quoted(0, Context::FlowOut)(state("'hello' rest")));
1728 assert!(c.contains(&Code::Text));
1729 }
1730
1731 #[test]
1732 fn c_single_quoted_consumes_through_closing_quote() {
1733 let reply = c_single_quoted(0, Context::FlowOut)(state("'hello' rest"));
1734 assert_eq!(remaining(&reply), " rest");
1735 }
1736
1737 #[test]
1738 fn c_single_quoted_accepts_empty_string() {
1739 let reply = c_single_quoted(0, Context::FlowOut)(state("'' rest"));
1740 assert!(is_success(&reply));
1741 let c = codes(c_single_quoted(0, Context::FlowOut)(state("'' rest")));
1742 assert!(c.contains(&Code::BeginScalar));
1743 assert!(c.contains(&Code::EndScalar));
1744 }
1745
1746 #[test]
1747 fn c_single_quoted_fails_without_opening_quote() {
1748 let reply = c_single_quoted(0, Context::FlowOut)(state("hello'"));
1749 assert!(is_failure(&reply));
1750 }
1751
1752 #[test]
1753 fn c_single_quoted_fails_without_closing_quote() {
1754 let reply = c_single_quoted(0, Context::FlowOut)(state("'hello"));
1755 assert!(is_failure(&reply));
1756 }
1757
1758 #[test]
1759 fn c_single_quoted_handles_escaped_single_quote() {
1760 let reply = c_single_quoted(0, Context::FlowOut)(state("'it''s fine'"));
1761 assert!(is_success(&reply));
1762 assert_eq!(remaining(&reply), "");
1763 }
1764
1765 #[test]
1766 fn c_quoted_quote_accepts_doubled_single_quote() {
1767 let reply = c_quoted_quote()(state("''rest"));
1768 assert!(is_success(&reply));
1769 assert_eq!(remaining(&reply), "rest");
1770 }
1771
1772 #[test]
1773 fn c_quoted_quote_fails_on_single_lone_quote() {
1774 let reply = c_quoted_quote()(state("'rest"));
1775 assert!(is_failure(&reply));
1776 }
1777
1778 #[test]
1779 fn nb_single_char_accepts_regular_char() {
1780 let reply = nb_single_char()(state("a"));
1781 assert!(is_success(&reply));
1782 }
1783
1784 #[test]
1785 fn nb_single_char_fails_on_bare_single_quote() {
1786 let reply = nb_single_char()(state("'rest"));
1787 assert!(is_failure(&reply));
1788 }
1789
1790 #[test]
1791 fn ns_single_char_fails_on_space() {
1792 let reply = ns_single_char()(state(" a"));
1793 assert!(is_failure(&reply));
1794 }
1795
1796 #[test]
1797 fn c_single_quoted_accepts_multiline() {
1798 let reply = c_single_quoted(0, Context::FlowOut)(state("'line1\nline2'"));
1799 assert!(is_success(&reply));
1800 }
1801
1802 #[test]
1807 fn ns_plain_first_accepts_regular_char_in_block_context() {
1808 let reply = crate::chars::ns_plain_first(Context::BlockOut)(state("hello"));
1809 assert!(is_success(&reply));
1810 }
1811
1812 #[test]
1813 fn ns_plain_first_accepts_question_when_followed_by_safe_char() {
1814 let reply = crate::chars::ns_plain_first(Context::FlowOut)(state("?value"));
1815 assert!(is_success(&reply));
1816 }
1817
1818 #[test]
1819 fn ns_plain_first_accepts_colon_when_followed_by_safe_char() {
1820 let reply = crate::chars::ns_plain_first(Context::FlowOut)(state(":value"));
1821 assert!(is_success(&reply));
1822 }
1823
1824 #[test]
1825 fn ns_plain_first_accepts_hyphen_when_followed_by_safe_char() {
1826 let reply = crate::chars::ns_plain_first(Context::FlowOut)(state("-value"));
1827 assert!(is_success(&reply));
1828 }
1829
1830 #[test]
1831 fn ns_plain_first_rejects_indicator_not_followed_by_safe_char() {
1832 let reply = crate::chars::ns_plain_first(Context::FlowOut)(state(": "));
1833 assert!(is_failure(&reply));
1834 }
1835
1836 #[test]
1837 fn ns_plain_char_accepts_hash_inside_scalar() {
1838 let reply = crate::chars::ns_plain_char(Context::BlockOut)(state("#rest"));
1839 assert!(is_success(&reply));
1840 }
1841
1842 #[test]
1843 fn ns_plain_char_accepts_colon_when_followed_by_safe_char() {
1844 let reply = crate::chars::ns_plain_char(Context::BlockOut)(state(":x"));
1845 assert!(is_success(&reply));
1846 }
1847
1848 #[test]
1849 fn ns_plain_char_rejects_colon_at_end_of_input() {
1850 let reply = crate::chars::ns_plain_char(Context::BlockOut)(state(":"));
1851 assert!(is_failure(&reply));
1852 }
1853
1854 #[test]
1855 fn ns_plain_accepts_simple_word_in_block_context() {
1856 let reply = ns_plain(0, Context::BlockOut)(state("hello"));
1859 assert!(is_success(&reply));
1860 assert_eq!(remaining(&reply), "");
1861 }
1862
1863 #[test]
1864 fn ns_plain_accepts_simple_word_in_flow_context() {
1865 let reply = ns_plain(0, Context::FlowOut)(state("hello"));
1866 assert!(is_success(&reply));
1867 assert_eq!(remaining(&reply), "");
1868 }
1869
1870 #[test]
1871 fn ns_plain_stops_at_newline_in_single_line_context() {
1872 let reply = ns_plain(0, Context::BlockOut)(state("hello\nrest"));
1877 assert!(is_success(&reply));
1878 assert_eq!(remaining(&reply), "");
1879 }
1880
1881 #[test]
1882 fn ns_plain_stops_at_flow_indicator_in_flow_context() {
1883 let reply = ns_plain(0, Context::FlowIn)(state("hello]rest"));
1884 assert!(is_success(&reply));
1885 assert_eq!(remaining(&reply), "]rest");
1886 }
1887
1888 #[test]
1889 fn ns_plain_allows_flow_indicator_in_block_context() {
1890 let reply = ns_plain(0, Context::BlockOut)(state("hello]rest"));
1891 assert!(is_success(&reply));
1892 assert_eq!(remaining(&reply), "");
1893 }
1894
1895 #[test]
1896 fn ns_plain_stops_at_colon_space_boundary() {
1897 let reply = ns_plain(0, Context::FlowOut)(state("key: value"));
1898 assert!(is_success(&reply));
1899 assert_eq!(remaining(&reply), ": value");
1900 }
1901
1902 #[test]
1903 fn ns_plain_stops_at_comma_in_flow_context() {
1904 let reply = ns_plain(0, Context::FlowIn)(state("hello,world"));
1905 assert!(is_success(&reply));
1906 assert_eq!(remaining(&reply), ",world");
1907 }
1908
1909 #[test]
1910 fn ns_plain_fails_when_starting_with_indicator() {
1911 let reply = ns_plain(0, Context::FlowOut)(state(",value"));
1912 assert!(is_failure(&reply));
1913 }
1914
1915 #[test]
1916 fn ns_plain_fails_when_starting_with_hash() {
1917 let reply = ns_plain(0, Context::BlockOut)(state("#comment"));
1918 assert!(is_failure(&reply));
1919 }
1920
1921 #[test]
1922 fn ns_plain_multi_line_continues_after_newline() {
1923 let reply = ns_plain(0, Context::BlockOut)(state("word1\n word2 rest"));
1924 assert!(is_success(&reply));
1925 }
1926
1927 #[test]
1928 fn ns_plain_multi_line_stops_when_continuation_indent_too_low() {
1929 let reply = ns_plain(2, Context::BlockOut)(state("word1\nword2 rest"));
1931 assert!(is_success(&reply));
1932 let rem = remaining(&reply);
1933 assert!(rem.contains("word2"));
1934 }
1935
1936 #[test]
1937 fn ns_plain_emits_begin_scalar() {
1938 let c = codes(ns_plain(0, Context::BlockOut)(state("hello")));
1939 assert_eq!(c.first().copied(), Some(Code::BeginScalar));
1940 }
1941
1942 #[test]
1943 fn ns_plain_emits_end_scalar() {
1944 let c = codes(ns_plain(0, Context::BlockOut)(state("hello")));
1945 assert_eq!(c.last().copied(), Some(Code::EndScalar));
1946 }
1947
1948 #[test]
1949 fn ns_plain_emits_text_for_content() {
1950 let c = codes(ns_plain(0, Context::BlockOut)(state("hello world")));
1951 assert!(c.contains(&Code::Text));
1952 }
1953
1954 #[test]
1955 fn ns_plain_safe_in_flow_rejects_flow_indicators() {
1956 let reply = crate::chars::ns_plain_safe(Context::FlowIn)(state(","));
1957 assert!(is_failure(&reply));
1958 }
1959
1960 #[test]
1966 fn c_flow_sequence_emits_begin_sequence() {
1967 let c = codes(c_flow_sequence(0, Context::FlowOut)(state("[a, b] rest")));
1968 assert_eq!(c.first().copied(), Some(Code::BeginSequence));
1969 }
1970
1971 #[test]
1972 fn c_flow_sequence_emits_end_sequence() {
1973 let c = codes(c_flow_sequence(0, Context::FlowOut)(state("[a, b] rest")));
1974 assert_eq!(c.last().copied(), Some(Code::EndSequence));
1975 }
1976
1977 #[test]
1978 fn c_flow_sequence_accepts_empty_sequence() {
1979 let reply = c_flow_sequence(0, Context::FlowOut)(state("[] rest"));
1980 assert!(is_success(&reply));
1981 let c = codes(c_flow_sequence(0, Context::FlowOut)(state("[] rest")));
1982 assert!(c.contains(&Code::BeginSequence));
1983 assert!(c.contains(&Code::EndSequence));
1984 assert_eq!(remaining(&reply), " rest");
1985 }
1986
1987 #[test]
1988 fn c_flow_sequence_accepts_single_entry() {
1989 let reply = c_flow_sequence(0, Context::FlowOut)(state("[hello] rest"));
1990 assert!(is_success(&reply));
1991 let c = codes(c_flow_sequence(0, Context::FlowOut)(state("[hello] rest")));
1992 assert!(c.contains(&Code::BeginScalar));
1993 }
1994
1995 #[test]
1996 fn c_flow_sequence_accepts_two_entries_with_comma() {
1997 let reply = c_flow_sequence(0, Context::FlowOut)(state("[a, b] rest"));
1998 assert!(is_success(&reply));
1999 assert_eq!(remaining(&reply), " rest");
2000 }
2001
2002 #[test]
2003 fn c_flow_sequence_accepts_trailing_comma() {
2004 let reply = c_flow_sequence(0, Context::FlowOut)(state("[a,] rest"));
2005 assert!(is_success(&reply));
2006 }
2007
2008 #[test]
2009 fn c_flow_sequence_fails_without_opening_bracket() {
2010 let reply = c_flow_sequence(0, Context::FlowOut)(state("a, b]"));
2011 assert!(is_failure(&reply));
2012 }
2013
2014 #[test]
2015 fn c_flow_sequence_fails_without_closing_bracket() {
2016 let reply = c_flow_sequence(0, Context::FlowOut)(state("[a, b"));
2017 assert!(is_failure(&reply));
2018 }
2019
2020 #[test]
2021 fn c_flow_sequence_accepts_nested_sequence() {
2022 let reply = c_flow_sequence(0, Context::FlowOut)(state("[[1,2],[3,4]] rest"));
2023 assert!(is_success(&reply));
2024 assert_eq!(remaining(&reply), " rest");
2025 }
2026
2027 #[test]
2028 fn c_flow_sequence_accepts_nested_mapping() {
2029 let reply = c_flow_sequence(0, Context::FlowOut)(state("[{a: b}] rest"));
2030 assert!(is_success(&reply));
2031 }
2032
2033 #[test]
2034 fn c_flow_sequence_accepts_double_quoted_entry() {
2035 let reply = c_flow_sequence(0, Context::FlowOut)(state("[\"hello\"] rest"));
2036 assert!(is_success(&reply));
2037 let c = codes(c_flow_sequence(0, Context::FlowOut)(state(
2038 "[\"hello\"] rest",
2039 )));
2040 assert!(c.contains(&Code::BeginScalar));
2041 }
2042
2043 #[test]
2044 fn c_flow_sequence_accepts_single_quoted_entry() {
2045 let reply = c_flow_sequence(0, Context::FlowOut)(state("['hello'] rest"));
2046 assert!(is_success(&reply));
2047 }
2048
2049 #[test]
2050 fn c_flow_sequence_entry_emits_begin_pair_for_explicit_key() {
2051 let reply = c_flow_sequence(0, Context::FlowOut)(state("[? key: val] rest"));
2052 assert!(is_success(&reply));
2053 let c = codes(c_flow_sequence(0, Context::FlowOut)(state(
2054 "[? key: val] rest",
2055 )));
2056 assert!(c.contains(&Code::BeginPair));
2057 }
2058
2059 #[test]
2060 fn c_flow_sequence_accepts_alias_node_entry() {
2061 let reply = c_flow_sequence(0, Context::FlowOut)(state("[*anchor] rest"));
2062 assert!(is_success(&reply));
2063 let c = codes(c_flow_sequence(0, Context::FlowOut)(state(
2064 "[*anchor] rest",
2065 )));
2066 assert!(c.contains(&Code::BeginAlias));
2067 }
2068
2069 #[test]
2070 fn c_flow_sequence_rejects_leading_comma() {
2071 let reply = c_flow_sequence(0, Context::FlowOut)(state("[ , ] rest"));
2072 assert!(is_failure(&reply));
2073 }
2074
2075 #[test]
2076 fn c_flow_sequence_inner_context_is_flow_in() {
2077 let reply = c_flow_sequence(0, Context::FlowOut)(state("[a,b,c]"));
2078 assert!(is_success(&reply));
2079 assert_eq!(remaining(&reply), "");
2080 }
2081
2082 #[test]
2083 fn c_flow_sequence_accepts_flow_pair_entry() {
2084 let reply = c_flow_sequence(0, Context::FlowOut)(state("[a: b] rest"));
2085 assert!(is_success(&reply));
2086 let c = codes(c_flow_sequence(0, Context::FlowOut)(state("[a: b] rest")));
2087 assert!(c.contains(&Code::BeginPair));
2088 assert!(c.contains(&Code::EndPair));
2089 }
2090
2091 #[test]
2092 fn c_flow_sequence_accepts_multiple_entries_no_spaces() {
2093 let reply = c_flow_sequence(0, Context::FlowOut)(state("[a,b,c] rest"));
2094 assert!(is_success(&reply));
2095 assert_eq!(remaining(&reply), " rest");
2096 }
2097
2098 #[test]
2099 fn c_flow_sequence_accepts_whitespace_around_entries() {
2100 let reply = c_flow_sequence(0, Context::FlowOut)(state("[ a , b ] rest"));
2101 assert!(is_success(&reply));
2102 assert_eq!(remaining(&reply), " rest");
2103 }
2104
2105 #[test]
2106 fn c_flow_sequence_accepts_multiline_entries() {
2107 let reply = c_flow_sequence(0, Context::FlowOut)(state("[\na,\nb\n] rest"));
2108 assert!(is_success(&reply));
2109 assert_eq!(remaining(&reply), " rest");
2110 }
2111
2112 #[test]
2113 fn c_flow_sequence_emits_indicator_for_brackets() {
2114 let c = codes(c_flow_sequence(0, Context::FlowOut)(state("[a]")));
2115 assert!(c.contains(&Code::Indicator));
2116 }
2117
2118 #[test]
2119 fn c_flow_sequence_emits_indicator_for_comma() {
2120 let c = codes(c_flow_sequence(0, Context::FlowOut)(state("[a,b]")));
2121 assert!(c.contains(&Code::Indicator));
2122 }
2123
2124 #[test]
2129 fn c_flow_mapping_emits_begin_mapping() {
2130 let c = codes(c_flow_mapping(0, Context::FlowOut)(state("{a: b} rest")));
2131 assert_eq!(c.first().copied(), Some(Code::BeginMapping));
2132 }
2133
2134 #[test]
2135 fn c_flow_mapping_emits_end_mapping() {
2136 let c = codes(c_flow_mapping(0, Context::FlowOut)(state("{a: b} rest")));
2137 assert_eq!(c.last().copied(), Some(Code::EndMapping));
2138 }
2139
2140 #[test]
2141 fn c_flow_mapping_accepts_empty_mapping() {
2142 let reply = c_flow_mapping(0, Context::FlowOut)(state("{} rest"));
2143 assert!(is_success(&reply));
2144 assert_eq!(remaining(&reply), " rest");
2145 }
2146
2147 #[test]
2148 fn c_flow_mapping_accepts_single_implicit_entry() {
2149 let reply = c_flow_mapping(0, Context::FlowOut)(state("{a: b} rest"));
2150 assert!(is_success(&reply));
2151 let c = codes(c_flow_mapping(0, Context::FlowOut)(state("{a: b} rest")));
2152 assert!(c.contains(&Code::BeginPair));
2153 assert!(c.contains(&Code::EndPair));
2154 }
2155
2156 #[test]
2157 fn c_flow_mapping_accepts_two_entries() {
2158 let reply = c_flow_mapping(0, Context::FlowOut)(state("{a: b, c: d} rest"));
2159 assert!(is_success(&reply));
2160 assert_eq!(remaining(&reply), " rest");
2161 }
2162
2163 #[test]
2164 fn c_flow_mapping_accepts_trailing_comma() {
2165 let reply = c_flow_mapping(0, Context::FlowOut)(state("{a: b,} rest"));
2166 assert!(is_success(&reply));
2167 }
2168
2169 #[test]
2170 fn c_flow_mapping_fails_without_opening_brace() {
2171 let reply = c_flow_mapping(0, Context::FlowOut)(state("a: b}"));
2172 assert!(is_failure(&reply));
2173 }
2174
2175 #[test]
2176 fn c_flow_mapping_fails_without_closing_brace() {
2177 let reply = c_flow_mapping(0, Context::FlowOut)(state("{a: b"));
2178 assert!(is_failure(&reply));
2179 }
2180
2181 #[test]
2182 fn c_flow_mapping_accepts_nested_mapping() {
2183 let reply = c_flow_mapping(0, Context::FlowOut)(state("{a: {b: c}} rest"));
2184 assert!(is_success(&reply));
2185 assert_eq!(remaining(&reply), " rest");
2186 }
2187
2188 #[test]
2189 fn c_flow_mapping_accepts_nested_sequence() {
2190 let reply = c_flow_mapping(0, Context::FlowOut)(state("{a: [1,2]} rest"));
2191 assert!(is_success(&reply));
2192 }
2193
2194 #[test]
2195 fn c_flow_mapping_accepts_colon_adjacent_value() {
2196 let reply = c_flow_mapping(0, Context::FlowOut)(state("{key:value} rest"));
2197 assert!(is_success(&reply));
2198 }
2199
2200 #[test]
2201 fn c_flow_mapping_accepts_explicit_key() {
2202 let reply = c_flow_mapping(0, Context::FlowOut)(state("{? key : value} rest"));
2203 assert!(is_success(&reply));
2204 let c = codes(c_flow_mapping(0, Context::FlowOut)(state(
2205 "{? key : value} rest",
2206 )));
2207 assert!(c.contains(&Code::BeginPair));
2208 }
2209
2210 #[test]
2211 fn c_flow_mapping_accepts_value_only_entry() {
2212 let reply = c_flow_mapping(0, Context::FlowOut)(state("{: value} rest"));
2213 assert!(is_success(&reply));
2214 }
2215
2216 #[test]
2217 fn c_flow_mapping_entry_emits_begin_pair() {
2218 let c = codes(c_flow_mapping(0, Context::FlowOut)(state("{a: b}")));
2219 assert!(c.contains(&Code::BeginPair));
2220 }
2221
2222 #[test]
2223 fn c_flow_mapping_entry_emits_end_pair() {
2224 let c = codes(c_flow_mapping(0, Context::FlowOut)(state("{a: b}")));
2225 assert!(c.contains(&Code::EndPair));
2226 }
2227
2228 #[test]
2229 fn c_flow_mapping_accepts_alias_as_value() {
2230 let reply = c_flow_mapping(0, Context::FlowOut)(state("{a: *anchor} rest"));
2231 assert!(is_success(&reply));
2232 let c = codes(c_flow_mapping(0, Context::FlowOut)(state(
2233 "{a: *anchor} rest",
2234 )));
2235 assert!(c.contains(&Code::BeginAlias));
2236 }
2237
2238 #[test]
2239 fn c_flow_mapping_accepts_double_quoted_key() {
2240 let reply = c_flow_mapping(0, Context::FlowOut)(state("{\"key\": value} rest"));
2241 assert!(is_success(&reply));
2242 }
2243
2244 #[test]
2245 fn c_flow_mapping_accepts_single_quoted_key() {
2246 let reply = c_flow_mapping(0, Context::FlowOut)(state("{'key': value} rest"));
2247 assert!(is_success(&reply));
2248 }
2249
2250 #[test]
2251 fn c_flow_mapping_accepts_multiline_entry() {
2252 let reply = c_flow_mapping(0, Context::FlowOut)(state("{\na: b\n} rest"));
2253 assert!(is_success(&reply));
2254 assert_eq!(remaining(&reply), " rest");
2255 }
2256
2257 #[test]
2258 fn c_flow_mapping_emits_indicator_for_braces() {
2259 let c = codes(c_flow_mapping(0, Context::FlowOut)(state("{a: b}")));
2260 assert!(c.contains(&Code::Indicator));
2261 }
2262
2263 #[test]
2264 fn c_flow_mapping_emits_indicator_for_colon() {
2265 let c = codes(c_flow_mapping(0, Context::FlowOut)(state("{a: b}")));
2266 assert!(c.contains(&Code::Indicator));
2267 }
2268
2269 #[test]
2270 fn c_flow_mapping_accepts_no_value_entry() {
2271 let reply = c_flow_mapping(0, Context::FlowOut)(state("{a} rest"));
2272 assert!(is_success(&reply));
2273 }
2274
2275 #[test]
2280 fn ns_flow_yaml_node_accepts_plain_scalar() {
2281 let reply = ns_flow_yaml_node(0, Context::FlowOut)(state("hello rest"));
2282 assert!(is_success(&reply));
2283 let c = codes(ns_flow_yaml_node(0, Context::FlowOut)(state("hello rest")));
2284 assert!(c.contains(&Code::BeginScalar));
2285 }
2286
2287 #[test]
2288 fn ns_flow_yaml_node_accepts_alias() {
2289 let reply = ns_flow_yaml_node(0, Context::FlowOut)(state("*anchor rest"));
2290 assert!(is_success(&reply));
2291 let c = codes(ns_flow_yaml_node(0, Context::FlowOut)(state(
2292 "*anchor rest",
2293 )));
2294 assert!(c.contains(&Code::BeginAlias));
2295 }
2296
2297 #[test]
2298 fn ns_flow_yaml_node_accepts_properties_then_scalar() {
2299 let reply = ns_flow_yaml_node(0, Context::FlowOut)(state("!!str hello rest"));
2300 assert!(is_success(&reply));
2301 let c = codes(ns_flow_yaml_node(0, Context::FlowOut)(state(
2302 "!!str hello rest",
2303 )));
2304 assert!(c.contains(&Code::BeginTag));
2305 assert!(c.contains(&Code::BeginScalar));
2306 }
2307
2308 #[test]
2309 fn ns_flow_yaml_node_accepts_properties_with_empty_node() {
2310 let reply = ns_flow_yaml_node(0, Context::FlowOut)(state("!!str "));
2311 assert!(is_success(&reply));
2312 }
2313
2314 #[test]
2315 fn c_flow_json_node_accepts_double_quoted_scalar() {
2316 let reply = c_flow_json_node(0, Context::FlowOut)(state("\"hello\" rest"));
2317 assert!(is_success(&reply));
2318 let c = codes(c_flow_json_node(0, Context::FlowOut)(state(
2319 "\"hello\" rest",
2320 )));
2321 assert!(c.contains(&Code::BeginScalar));
2322 }
2323
2324 #[test]
2325 fn c_flow_json_node_accepts_single_quoted_scalar() {
2326 let reply = c_flow_json_node(0, Context::FlowOut)(state("'hello' rest"));
2327 assert!(is_success(&reply));
2328 let c = codes(c_flow_json_node(0, Context::FlowOut)(state("'hello' rest")));
2329 assert!(c.contains(&Code::BeginScalar));
2330 }
2331
2332 #[test]
2333 fn c_flow_json_node_accepts_flow_sequence() {
2334 let reply = c_flow_json_node(0, Context::FlowOut)(state("[a, b] rest"));
2335 assert!(is_success(&reply));
2336 let c = codes(c_flow_json_node(0, Context::FlowOut)(state("[a, b] rest")));
2337 assert!(c.contains(&Code::BeginSequence));
2338 }
2339
2340 #[test]
2341 fn c_flow_json_node_accepts_flow_mapping() {
2342 let reply = c_flow_json_node(0, Context::FlowOut)(state("{a: b} rest"));
2343 assert!(is_success(&reply));
2344 let c = codes(c_flow_json_node(0, Context::FlowOut)(state("{a: b} rest")));
2345 assert!(c.contains(&Code::BeginMapping));
2346 }
2347
2348 #[test]
2349 fn c_flow_json_node_fails_on_plain_scalar() {
2350 let reply = c_flow_json_node(0, Context::FlowOut)(state("hello rest"));
2351 assert!(is_failure(&reply));
2352 }
2353
2354 #[test]
2355 fn ns_flow_node_accepts_yaml_node() {
2356 let reply = ns_flow_node(0, Context::FlowOut)(state("hello rest"));
2357 assert!(is_success(&reply));
2358 }
2359
2360 #[test]
2361 fn ns_flow_node_accepts_json_node() {
2362 let reply = ns_flow_node(0, Context::FlowOut)(state("\"hello\" rest"));
2363 assert!(is_success(&reply));
2364 }
2365
2366 #[test]
2367 fn c_ns_flow_pair_accepts_implicit_key_value() {
2368 let reply = c_ns_flow_pair(0, Context::FlowOut)(state("key: value rest"));
2369 assert!(is_success(&reply));
2370 let c = codes(c_ns_flow_pair(0, Context::FlowOut)(state(
2371 "key: value rest",
2372 )));
2373 assert!(c.contains(&Code::BeginPair));
2374 assert!(c.contains(&Code::EndPair));
2375 }
2376
2377 #[test]
2378 fn c_ns_flow_pair_accepts_explicit_key() {
2379 let reply = c_ns_flow_pair(0, Context::FlowOut)(state("? key : value rest"));
2380 assert!(is_success(&reply));
2381 let c = codes(c_ns_flow_pair(0, Context::FlowOut)(state(
2382 "? key : value rest",
2383 )));
2384 assert!(c.contains(&Code::BeginPair));
2385 }
2386
2387 #[test]
2388 fn c_ns_flow_pair_accepts_value_with_no_key() {
2389 let reply = c_ns_flow_pair(0, Context::FlowOut)(state(": value rest"));
2390 assert!(is_success(&reply));
2391 }
2392
2393 #[test]
2394 fn c_ns_flow_pair_emits_indicator_for_colon() {
2395 let c = codes(c_ns_flow_pair(0, Context::FlowOut)(state("key: value")));
2396 assert!(c.contains(&Code::Indicator));
2397 }
2398
2399 #[test]
2400 fn ns_flow_yaml_node_accepts_properties_then_flow_mapping() {
2401 let reply = ns_flow_yaml_node(0, Context::FlowOut)(state("!!map {a: b} rest"));
2402 assert!(is_success(&reply));
2403 let c = codes(ns_flow_yaml_node(0, Context::FlowOut)(state(
2404 "!!map {a: b} rest",
2405 )));
2406 assert!(c.contains(&Code::BeginTag));
2407 assert!(c.contains(&Code::BeginMapping));
2408 }
2409}