@@ -12,8 +12,10 @@ use nom::{
12
12
IResult ,
13
13
} ;
14
14
use std:: {
15
+ borrow:: Cow ,
15
16
collections:: { btree_map:: Entry , BTreeMap } ,
16
- str:: FromStr ,
17
+ iter:: Peekable ,
18
+ str:: { Chars , FromStr } ,
17
19
} ;
18
20
19
21
pub ( crate ) fn parse_key_value (
@@ -346,7 +348,7 @@ fn parse_key_value_<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
346
348
parse_value ( field_delimiter) ,
347
349
) ) ( input) ,
348
350
} ,
349
- |( field, sep, value) : ( & str , Vec < & str > , Value ) | {
351
+ |( field, sep, value) : ( Cow < ' _ , str > , Vec < & str > , Value ) | {
350
352
(
351
353
field. to_string ( ) . into ( ) ,
352
354
if sep. len ( ) == 1 { value } else { value ! ( true ) } ,
@@ -356,6 +358,45 @@ fn parse_key_value_<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
356
358
}
357
359
}
358
360
361
+ fn escape_str ( s : & str ) -> Cow < ' _ , str > {
362
+ if s. contains ( '\\' ) {
363
+ let mut out = String :: new ( ) ;
364
+ let mut chars = s. chars ( ) . peekable ( ) ;
365
+
366
+ while let Some ( c) = chars. next ( ) {
367
+ out. push ( escape_char ( c, & mut chars) )
368
+ }
369
+ Cow :: Owned ( out)
370
+ } else {
371
+ Cow :: Borrowed ( s)
372
+ }
373
+ }
374
+
375
+ fn escape_char ( c : char , rest : & mut Peekable < Chars > ) -> char {
376
+ if c == '\\' {
377
+ match rest. peek ( ) {
378
+ Some ( 'n' ) => {
379
+ let _ = rest. next ( ) ;
380
+ '\n'
381
+ }
382
+ Some ( '\\' ) => {
383
+ let _ = rest. next ( ) ;
384
+ '\\'
385
+ }
386
+ Some ( '"' ) => {
387
+ let _ = rest. next ( ) ;
388
+ '\"'
389
+ }
390
+ // ignore escape sequences not added by encode_key_value and return the backslash untouched
391
+ Some ( _) => c,
392
+ // trailing escape char is a little odd... Might need to error here!
393
+ None => c,
394
+ }
395
+ } else {
396
+ c
397
+ }
398
+ }
399
+
359
400
/// Parses a string delimited by the given character.
360
401
/// Can be escaped using `\`.
361
402
/// The terminator indicates the character that should follow the delimited field.
@@ -367,7 +408,7 @@ fn parse_key_value_<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
367
408
fn parse_delimited < ' a , E : ParseError < & ' a str > + ContextError < & ' a str > > (
368
409
delimiter : char ,
369
410
field_terminator : & ' a str ,
370
- ) -> impl Fn ( & ' a str ) -> IResult < & ' a str , & ' a str , E > {
411
+ ) -> impl Fn ( & ' a str ) -> IResult < & ' a str , Cow < ' a , str > , E > {
371
412
move |input| {
372
413
terminated (
373
414
delimited (
@@ -379,7 +420,8 @@ fn parse_delimited<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
379
420
// match literally any character, there are no invalid escape sequences
380
421
take ( 1usize ) ,
381
422
) ) ,
382
- |inner| inner. unwrap_or ( "" ) ,
423
+ // process the escape sequences that we encode
424
+ |inner| inner. map_or ( Cow :: Borrowed ( "" ) , escape_str) ,
383
425
) ,
384
426
char ( delimiter) ,
385
427
) ,
@@ -395,8 +437,12 @@ fn parse_delimited<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
395
437
/// just take the rest of the string.
396
438
fn parse_undelimited < ' a , E : ParseError < & ' a str > + ContextError < & ' a str > > (
397
439
field_delimiter : & ' a str ,
398
- ) -> impl Fn ( & ' a str ) -> IResult < & ' a str , & ' a str , E > {
399
- move |input| map ( alt ( ( take_until ( field_delimiter) , rest) ) , str:: trim) ( input)
440
+ ) -> impl Fn ( & ' a str ) -> IResult < & ' a str , Cow < ' a , str > , E > {
441
+ move |input| {
442
+ map ( alt ( ( take_until ( field_delimiter) , rest) ) , |s : & ' _ str | {
443
+ Cow :: Borrowed ( s. trim ( ) )
444
+ } ) ( input)
445
+ }
400
446
}
401
447
402
448
/// Parses the value.
@@ -421,14 +467,16 @@ fn parse_value<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
421
467
}
422
468
}
423
469
470
+ type ParseKeyIResult < ' a , E > = IResult < & ' a str , Cow < ' a , str > , E > ;
471
+
424
472
/// Parses the key.
425
473
/// Overall parsing strategies are the same as `parse_value`, but we don't need to convert the result to a `Value`.
426
474
/// Standalone key are handled here so a quoted standalone key that contains a delimiter will be dealt with correctly.
427
475
fn parse_key < ' a , E : ParseError < & ' a str > + ContextError < & ' a str > > (
428
476
key_value_delimiter : & ' a str ,
429
477
field_delimiter : & ' a str ,
430
478
standalone_key : bool ,
431
- ) -> Box < dyn Fn ( & ' a str ) -> IResult < & ' a str , & ' a str , E > + ' a > {
479
+ ) -> Box < dyn Fn ( & ' a str ) -> ParseKeyIResult < ' a , E > + ' a > {
432
480
if standalone_key {
433
481
Box :: new ( move |input| {
434
482
verify (
@@ -630,37 +678,37 @@ mod test {
630
678
fn test_parse_key ( ) {
631
679
// delimited
632
680
assert_eq ! (
633
- Ok ( ( "" , "noog" ) ) ,
681
+ Ok ( ( "" , Cow :: Borrowed ( "noog" ) ) ) ,
634
682
parse_key:: <VerboseError <& str >>( "=" , " " , false ) ( r#""noog""# )
635
683
) ;
636
684
637
685
// undelimited
638
686
assert_eq ! (
639
- Ok ( ( "" , "noog" ) ) ,
687
+ Ok ( ( "" , Cow :: Borrowed ( "noog" ) ) ) ,
640
688
parse_key:: <VerboseError <& str >>( "=" , " " , false ) ( "noog" )
641
689
) ;
642
690
643
691
// delimited with escaped char (1)
644
692
assert_eq ! (
645
- Ok ( ( "=baz" , r#"foo \ " bar"# ) ) ,
693
+ Ok ( ( "=baz" , Cow :: Borrowed ( r#"foo " bar"# ) ) ) ,
646
694
parse_key:: <VerboseError <& str >>( "=" , " " , false ) ( r#""foo \" bar"=baz"# )
647
695
) ;
648
696
649
697
// delimited with escaped char (2)
650
698
assert_eq ! (
651
- Ok ( ( "=baz" , r#"foo \\ \ " \ bar"# ) ) ,
699
+ Ok ( ( "=baz" , Cow :: Borrowed ( r#"foo \ " \ bar"# ) ) ) ,
652
700
parse_key:: <VerboseError <& str >>( "=" , " " , false ) ( r#""foo \\ \" \ bar"=baz"# )
653
701
) ;
654
702
655
703
// delimited with escaped char (3)
656
704
assert_eq ! (
657
- Ok ( ( "=baz" , r"foo \ bar" ) ) ,
705
+ Ok ( ( "=baz" , Cow :: Borrowed ( r"foo \ bar" ) ) ) ,
658
706
parse_key:: <VerboseError <& str >>( "=" , " " , false ) ( r#""foo \ bar"=baz"# )
659
707
) ;
660
708
661
709
// Standalone key
662
710
assert_eq ! (
663
- Ok ( ( " bar=baz" , "foo" ) ) ,
711
+ Ok ( ( " bar=baz" , Cow :: Borrowed ( "foo" ) ) ) ,
664
712
parse_key:: <VerboseError <& str >>( "=" , " " , true ) ( "foo bar=baz" )
665
713
) ;
666
714
@@ -703,7 +751,7 @@ mod test {
703
751
#[ test]
704
752
fn test_parse_delimited_with_single_quotes ( ) {
705
753
assert_eq ! (
706
- Ok ( ( "" , "test" ) ) ,
754
+ Ok ( ( "" , Cow :: Borrowed ( "test" ) ) ) ,
707
755
parse_delimited:: <VerboseError <& str >>( '\'' , " " ) ( "'test'" )
708
756
) ;
709
757
}
@@ -747,15 +795,15 @@ mod test {
747
795
#[ test]
748
796
fn test_parse_delimited_with_internal_delimiters ( ) {
749
797
assert_eq ! (
750
- Ok ( ( "" , "noog nonk" ) ) ,
798
+ Ok ( ( "" , Cow :: Borrowed ( "noog nonk" ) ) ) ,
751
799
parse_delimited:: <VerboseError <& str >>( '"' , " " ) ( r#""noog nonk""# )
752
800
) ;
753
801
}
754
802
755
803
#[ test]
756
804
fn test_parse_undelimited_with_quotes ( ) {
757
805
assert_eq ! (
758
- Ok ( ( "" , r#""noog" nonk"# ) ) ,
806
+ Ok ( ( "" , Cow :: Borrowed ( r#""noog" nonk"# ) ) ) ,
759
807
parse_undelimited:: <VerboseError <& str >>( ":" ) ( r#""noog" nonk"# )
760
808
) ;
761
809
}
@@ -829,7 +877,7 @@ mod test {
829
877
value: r#""zork one" : "zoog\"zink\"zork" nonk : nink"# ,
830
878
key_value_delimiter: ":" ,
831
879
] ,
832
- want: Ok ( value!( { "zork one" : r#"zoog\ "zink\ "zork"# ,
880
+ want: Ok ( value!( { "zork one" : r#"zoog"zink"zork"# ,
833
881
nonk: "nink" } ) ) ,
834
882
tdef: type_def( ) ,
835
883
}
@@ -840,7 +888,7 @@ mod test {
840
888
key_value_delimiter: ":" ,
841
889
field_delimiter: "," ,
842
890
] ,
843
- want: Ok ( value!( { "zork one" : r#"zoog\ "zink\ "zork"# ,
891
+ want: Ok ( value!( { "zork one" : r#"zoog"zink"zork"# ,
844
892
nonk: "nink" } ) ) ,
845
893
tdef: type_def( ) ,
846
894
}
@@ -851,7 +899,7 @@ mod test {
851
899
key_value_delimiter: ":" ,
852
900
field_delimiter: "," ,
853
901
] ,
854
- want: Ok ( value!( { "zork one" : r#"zoog\ "zink\ "zork"# ,
902
+ want: Ok ( value!( { "zork one" : r#"zoog"zink"zork"# ,
855
903
nonk: "nink" } ) ) ,
856
904
tdef: type_def( ) ,
857
905
}
@@ -862,7 +910,7 @@ mod test {
862
910
key_value_delimiter: "--" ,
863
911
field_delimiter: "||" ,
864
912
] ,
865
- want: Ok ( value!( { "zork one" : r#"zoog\ "zink\ "zork"# ,
913
+ want: Ok ( value!( { "zork one" : r#"zoog"zink"zork"# ,
866
914
nonk: "nink" } ) ) ,
867
915
tdef: type_def( ) ,
868
916
}
@@ -968,7 +1016,7 @@ mod test {
968
1016
field_delimiter: " " ,
969
1017
] ,
970
1018
want: Ok ( value!( {
971
- "field" : "quote -> \\ \ " <-" ,
1019
+ "field" : "quote -> \" <-" ,
972
1020
"level" : "info" ,
973
1021
} ) ) ,
974
1022
tdef: type_def( ) ,
0 commit comments