1use core::fmt;
2use core::str;
3
4use memchr::memchr;
5
6use crate::{QuoteStyle, Terminator};
7
8#[derive(Debug)]
13pub struct WriterBuilder {
14 wtr: Writer,
15}
16
17impl WriterBuilder {
18 pub fn new() -> WriterBuilder {
20 let wtr = Writer {
21 state: WriterState::default(),
22 requires_quotes: [false; 256],
23 delimiter: b',',
24 term: Terminator::Any(b'\n'),
25 style: QuoteStyle::default(),
26 quote: b'"',
27 escape: b'\\',
28 double_quote: true,
29 comment: None,
30 };
31 WriterBuilder { wtr }
32 }
33
34 pub fn build(&self) -> Writer {
36 use crate::Terminator::*;
37
38 let mut wtr = self.wtr.clone();
39 wtr.requires_quotes[self.wtr.delimiter as usize] = true;
40 wtr.requires_quotes[self.wtr.quote as usize] = true;
41 if !self.wtr.double_quote {
42 wtr.requires_quotes[self.wtr.escape as usize] = true;
45 }
46 match self.wtr.term {
47 CRLF | Any(b'\n') | Any(b'\r') => {
48 wtr.requires_quotes[b'\r' as usize] = true;
53 wtr.requires_quotes[b'\n' as usize] = true;
54 }
55 Any(b) => {
56 wtr.requires_quotes[b as usize] = true;
57 }
58 }
59 if let Some(comment) = self.wtr.comment {
64 wtr.requires_quotes[comment as usize] = true;
65 }
66 wtr
67 }
68
69 pub fn delimiter(&mut self, delimiter: u8) -> &mut WriterBuilder {
73 self.wtr.delimiter = delimiter;
74 self
75 }
76
77 pub fn terminator(&mut self, term: Terminator) -> &mut WriterBuilder {
84 self.wtr.term = term;
85 self
86 }
87
88 pub fn quote_style(&mut self, style: QuoteStyle) -> &mut WriterBuilder {
96 self.wtr.style = style;
97 self
98 }
99
100 pub fn quote(&mut self, quote: u8) -> &mut WriterBuilder {
104 self.wtr.quote = quote;
105 self
106 }
107
108 pub fn escape(&mut self, escape: u8) -> &mut WriterBuilder {
114 self.wtr.escape = escape;
115 self
116 }
117
118 pub fn double_quote(&mut self, yes: bool) -> &mut WriterBuilder {
126 self.wtr.double_quote = yes;
127 self
128 }
129
130 pub fn comment(&mut self, comment: Option<u8>) -> &mut WriterBuilder {
137 self.wtr.comment = comment;
138 self
139 }
140}
141
142impl Default for WriterBuilder {
143 fn default() -> WriterBuilder {
144 WriterBuilder::new()
145 }
146}
147
148#[derive(Clone, Debug, Eq, PartialEq)]
155pub enum WriteResult {
156 InputEmpty,
159 OutputFull,
164}
165
166pub struct Writer {
179 state: WriterState,
180 requires_quotes: [bool; 256],
181 delimiter: u8,
182 term: Terminator,
183 style: QuoteStyle,
184 quote: u8,
185 escape: u8,
186 double_quote: bool,
187 comment: Option<u8>,
188}
189
190impl Clone for Writer {
191 fn clone(&self) -> Writer {
192 Writer {
193 state: self.state.clone(),
194 requires_quotes: self.requires_quotes,
195 delimiter: self.delimiter,
196 term: self.term,
197 style: self.style,
198 quote: self.quote,
199 escape: self.escape,
200 double_quote: self.double_quote,
201 comment: self.comment,
202 }
203 }
204}
205
206impl fmt::Debug for Writer {
207 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
208 f.debug_struct("Writer")
209 .field("state", &self.state)
210 .field("delimiter", &self.delimiter)
211 .field("term", &self.term)
212 .field("style", &self.style)
213 .field("quote", &self.quote)
214 .field("escape", &self.escape)
215 .field("double_quote", &self.double_quote)
216 .finish()
217 }
218}
219
220#[derive(Clone, Debug)]
221struct WriterState {
222 in_field: bool,
226 quoting: bool,
230 record_bytes: u64,
235}
236
237impl Writer {
238 pub fn new() -> Writer {
240 Writer::default()
241 }
242
243 pub fn finish(&mut self, mut output: &mut [u8]) -> (WriteResult, usize) {
248 let mut nout = 0;
249 if self.state.record_bytes == 0 && self.state.in_field {
250 assert!(!self.state.quoting);
251 let (res, o) = self.write(&[self.quote, self.quote], output);
252 if o == 0 {
253 return (res, 0);
254 }
255 output = &mut moving(output)[o..];
256 nout += o;
257 self.state.record_bytes += o as u64;
258 }
259 if !self.state.quoting {
260 return (WriteResult::InputEmpty, nout);
261 }
262 let (res, o) = self.write(&[self.quote], output);
263 if o == 0 {
264 return (res, nout);
265 }
266 nout += o;
267 self.state.record_bytes = 0;
268 self.state.in_field = false;
269 self.state.quoting = false;
270 (res, nout)
271 }
272
273 pub fn field(
296 &mut self,
297 input: &[u8],
298 mut output: &mut [u8],
299 ) -> (WriteResult, usize, usize) {
300 let (mut nin, mut nout) = (0, 0);
301
302 if !self.state.in_field {
303 self.state.quoting = self.should_quote(input);
304 if self.state.quoting {
305 let (res, o) = self.write(&[self.quote], output);
306 if o == 0 {
307 return (res, 0, 0);
308 }
309 output = &mut moving(output)[o..];
310 nout += o;
311 self.state.record_bytes += o as u64;
312 }
313 self.state.in_field = true;
314 }
315 let (res, i, o) = if self.state.quoting {
316 quote(input, output, self.quote, self.escape, self.double_quote)
317 } else {
318 write_optimistic(input, output)
319 };
320 nin += i;
321 nout += o;
322 self.state.record_bytes += o as u64;
323 (res, nin, nout)
324 }
325
326 pub fn delimiter(
335 &mut self,
336 mut output: &mut [u8],
337 ) -> (WriteResult, usize) {
338 let mut nout = 0;
339 if self.state.quoting {
340 let (res, o) = self.write(&[self.quote], output);
341 if o == 0 {
342 return (res, o);
343 }
344 output = &mut moving(output)[o..];
345 nout += o;
346 self.state.record_bytes += o as u64;
347 self.state.quoting = false;
348 }
349 let (res, o) = self.write(&[self.delimiter], output);
350 if o == 0 {
351 return (res, nout);
352 }
353 nout += o;
354 self.state.record_bytes += o as u64;
355 self.state.in_field = false;
356 (res, nout)
357 }
358
359 pub fn terminator(
367 &mut self,
368 mut output: &mut [u8],
369 ) -> (WriteResult, usize) {
370 let mut nout = 0;
371 if self.state.record_bytes == 0 {
372 assert!(!self.state.quoting);
373 let (res, o) = self.write(&[self.quote, self.quote], output);
374 if o == 0 {
375 return (res, 0);
376 }
377 output = &mut moving(output)[o..];
378 nout += o;
379 self.state.record_bytes += o as u64;
380 }
381 if self.state.quoting {
382 let (res, o) = self.write(&[self.quote], output);
383 if o == 0 {
384 return (res, o);
385 }
386 output = &mut moving(output)[o..];
387 nout += o;
388 self.state.record_bytes += o as u64;
389 self.state.quoting = false;
390 }
391 let (res, o) = match self.term {
392 Terminator::CRLF => write_pessimistic(b"\r\n", output),
393 Terminator::Any(b) => write_pessimistic(&[b], output),
394 };
395 if o == 0 {
396 return (res, nout);
397 }
398 nout += o;
399 self.state.record_bytes = 0;
400 self.state.in_field = false;
401 (res, nout)
402 }
403
404 #[inline]
408 fn needs_quotes(&self, mut input: &[u8]) -> bool {
409 let mut needs = false;
410 while !needs && input.len() >= 8 {
411 needs = self.requires_quotes[input[0] as usize]
412 || self.requires_quotes[input[1] as usize]
413 || self.requires_quotes[input[2] as usize]
414 || self.requires_quotes[input[3] as usize]
415 || self.requires_quotes[input[4] as usize]
416 || self.requires_quotes[input[5] as usize]
417 || self.requires_quotes[input[6] as usize]
418 || self.requires_quotes[input[7] as usize];
419 input = &input[8..];
420 }
421 needs || input.iter().any(|&b| self.is_special_byte(b))
422 }
423
424 #[inline]
430 pub fn is_special_byte(&self, b: u8) -> bool {
431 self.requires_quotes[b as usize]
432 }
433
434 #[inline]
437 pub fn should_quote(&self, input: &[u8]) -> bool {
438 match self.style {
439 QuoteStyle::Always => true,
440 QuoteStyle::Never => false,
441 QuoteStyle::NonNumeric => is_non_numeric(input),
442 QuoteStyle::Necessary => self.needs_quotes(input),
443 }
444 }
445
446 #[inline]
448 pub fn get_delimiter(&self) -> u8 {
449 self.delimiter
450 }
451
452 #[inline]
454 pub fn get_terminator(&self) -> Terminator {
455 self.term
456 }
457
458 #[inline]
460 pub fn get_quote_style(&self) -> QuoteStyle {
461 self.style
462 }
463
464 #[inline]
466 pub fn get_quote(&self) -> u8 {
467 self.quote
468 }
469
470 #[inline]
472 pub fn get_escape(&self) -> u8 {
473 self.escape
474 }
475
476 #[inline]
479 pub fn get_double_quote(&self) -> bool {
480 self.double_quote
481 }
482
483 fn write(&self, data: &[u8], output: &mut [u8]) -> (WriteResult, usize) {
484 if data.len() > output.len() {
485 (WriteResult::OutputFull, 0)
486 } else {
487 output[..data.len()].copy_from_slice(data);
488 (WriteResult::InputEmpty, data.len())
489 }
490 }
491}
492
493impl Default for Writer {
494 fn default() -> Writer {
495 WriterBuilder::new().build()
496 }
497}
498
499impl Default for WriterState {
500 fn default() -> WriterState {
501 WriterState { in_field: false, quoting: false, record_bytes: 0 }
502 }
503}
504
505pub fn is_non_numeric(input: &[u8]) -> bool {
507 let s = match str::from_utf8(input) {
508 Err(_) => return true,
509 Ok(s) => s,
510 };
511 s.parse::<f64>().is_err() && s.parse::<i128>().is_err()
515}
516
517pub fn quote(
542 mut input: &[u8],
543 mut output: &mut [u8],
544 quote: u8,
545 escape: u8,
546 double_quote: bool,
547) -> (WriteResult, usize, usize) {
548 let (mut nin, mut nout) = (0, 0);
549 loop {
550 match memchr(quote, input) {
551 None => {
552 let (res, i, o) = write_optimistic(input, output);
553 nin += i;
554 nout += o;
555 return (res, nin, nout);
556 }
557 Some(next_quote) => {
558 let (res, i, o) =
559 write_optimistic(&input[..next_quote], output);
560 input = &input[i..];
561 output = &mut moving(output)[o..];
562 nin += i;
563 nout += o;
564 if let WriteResult::OutputFull = res {
565 return (res, nin, nout);
566 }
567 if double_quote {
568 let (res, o) = write_pessimistic(&[quote, quote], output);
569 if let WriteResult::OutputFull = res {
570 return (res, nin, nout);
571 }
572 nout += o;
573 output = &mut moving(output)[o..];
574 } else {
575 let (res, o) = write_pessimistic(&[escape, quote], output);
576 if let WriteResult::OutputFull = res {
577 return (res, nin, nout);
578 }
579 nout += o;
580 output = &mut moving(output)[o..];
581 }
582 nin += 1;
583 input = &input[1..];
584 }
585 }
586 }
587}
588
589fn write_optimistic(
601 input: &[u8],
602 output: &mut [u8],
603) -> (WriteResult, usize, usize) {
604 if input.len() > output.len() {
605 let input = &input[..output.len()];
606 output.copy_from_slice(input);
607 (WriteResult::OutputFull, output.len(), output.len())
608 } else {
609 output[..input.len()].copy_from_slice(input);
610 (WriteResult::InputEmpty, input.len(), input.len())
611 }
612}
613
614fn write_pessimistic(input: &[u8], output: &mut [u8]) -> (WriteResult, usize) {
620 if input.len() > output.len() {
621 (WriteResult::OutputFull, 0)
622 } else {
623 output[..input.len()].copy_from_slice(input);
624 (WriteResult::InputEmpty, input.len())
625 }
626}
627
628fn moving<T>(x: T) -> T {
631 x
632}
633
634#[cfg(test)]
635mod tests {
636 use crate::writer::WriteResult::*;
637 use crate::writer::{quote, QuoteStyle, Writer, WriterBuilder};
638
639 fn b(s: &str) -> &[u8] {
641 s.as_bytes()
642 }
643 fn s(b: &[u8]) -> &str {
644 ::core::str::from_utf8(b).unwrap()
645 }
646
647 macro_rules! assert_field {
648 (
649 $wtr:expr, $inp:expr, $out:expr,
650 $expect_in:expr, $expect_out:expr,
651 $expect_res:expr, $expect_data:expr
652 ) => {{
653 let (res, i, o) = $wtr.field($inp, $out);
654 assert_eq!($expect_res, res, "result");
655 assert_eq!($expect_in, i, "input");
656 assert_eq!($expect_out, o, "output");
657 assert_eq!($expect_data, s(&$out[..o]), "data");
658 }};
659 }
660
661 macro_rules! assert_write {
662 (
663 $wtr:expr, $which:ident, $out:expr,
664 $expect_out:expr, $expect_res:expr, $expect_data:expr
665 ) => {{
666 let (res, o) = $wtr.$which($out);
667 assert_eq!($expect_res, res, "result");
668 assert_eq!($expect_out, o, "output");
669 assert_eq!($expect_data, s(&$out[..o]), "data");
670 }};
671 }
672
673 #[test]
674 fn writer_one_field() {
675 let mut wtr = Writer::new();
676 let out = &mut [0; 1024];
677 let mut n = 0;
678
679 assert_field!(wtr, b("abc"), &mut out[n..], 3, 3, InputEmpty, "abc");
680 n += 3;
681
682 assert_write!(wtr, finish, &mut out[n..], 0, InputEmpty, "");
683 }
684
685 #[test]
686 fn writer_one_empty_field_terminator() {
687 let mut wtr = Writer::new();
688 let out = &mut [0; 1024];
689
690 assert_field!(wtr, b(""), &mut out[..], 0, 0, InputEmpty, "");
691 assert_write!(wtr, terminator, &mut out[..], 3, InputEmpty, "\"\"\n");
692 assert_write!(wtr, finish, &mut out[..], 0, InputEmpty, "");
693 }
694
695 #[test]
696 fn writer_one_empty_field_finish() {
697 let mut wtr = Writer::new();
698 let out = &mut [0; 1024];
699
700 assert_field!(wtr, b(""), &mut out[..], 0, 0, InputEmpty, "");
701 assert_write!(wtr, finish, &mut out[..], 2, InputEmpty, "\"\"");
702 }
703
704 #[test]
705 fn writer_many_one_empty_field_finish() {
706 let mut wtr = Writer::new();
707 let out = &mut [0; 1024];
708
709 assert_field!(wtr, b(""), &mut out[..], 0, 0, InputEmpty, "");
710 assert_write!(wtr, terminator, &mut out[..], 3, InputEmpty, "\"\"\n");
711 assert_field!(wtr, b(""), &mut out[..], 0, 0, InputEmpty, "");
712 assert_write!(wtr, finish, &mut out[..], 2, InputEmpty, "\"\"");
713 }
714
715 #[test]
716 fn writer_many_one_empty_field_terminator() {
717 let mut wtr = Writer::new();
718 let out = &mut [0; 1024];
719
720 assert_field!(wtr, b(""), &mut out[..], 0, 0, InputEmpty, "");
721 assert_write!(wtr, terminator, &mut out[..], 3, InputEmpty, "\"\"\n");
722 assert_field!(wtr, b(""), &mut out[..], 0, 0, InputEmpty, "");
723 assert_write!(wtr, terminator, &mut out[..], 3, InputEmpty, "\"\"\n");
724 assert_write!(wtr, finish, &mut out[..], 0, InputEmpty, "");
725 }
726
727 #[test]
728 fn writer_one_field_quote() {
729 let mut wtr = Writer::new();
730 let out = &mut [0; 1024];
731 let mut n = 0;
732
733 assert_field!(
734 wtr,
735 b("a\"bc"),
736 &mut out[n..],
737 4,
738 6,
739 InputEmpty,
740 "\"a\"\"bc"
741 );
742 n += 6;
743
744 assert_write!(wtr, finish, &mut out[n..], 1, InputEmpty, "\"");
745 }
746
747 #[test]
748 fn writer_one_field_stream() {
749 let mut wtr = Writer::new();
750 let out = &mut [0; 1024];
751 let mut n = 0;
752
753 assert_field!(wtr, b("abc"), &mut out[n..], 3, 3, InputEmpty, "abc");
754 n += 3;
755 assert_field!(wtr, b("x"), &mut out[n..], 1, 1, InputEmpty, "x");
756 n += 1;
757
758 assert_write!(wtr, finish, &mut out[n..], 0, InputEmpty, "");
759 }
760
761 #[test]
762 fn writer_one_field_stream_quote() {
763 let mut wtr = Writer::new();
764 let out = &mut [0; 1024];
765 let mut n = 0;
766
767 assert_field!(
768 wtr,
769 b("abc\""),
770 &mut out[n..],
771 4,
772 6,
773 InputEmpty,
774 "\"abc\"\""
775 );
776 n += 6;
777 assert_field!(wtr, b("x"), &mut out[n..], 1, 1, InputEmpty, "x");
778 n += 1;
779
780 assert_write!(wtr, finish, &mut out[n..], 1, InputEmpty, "\"");
781 }
782
783 #[test]
784 fn writer_one_field_stream_quote_partial() {
785 let mut wtr = Writer::new();
786 let out = &mut [0; 4];
787
788 assert_field!(wtr, b("ab\"xyz"), out, 2, 3, OutputFull, "\"ab");
789 assert_field!(wtr, b("\"xyz"), out, 3, 4, OutputFull, "\"\"xy");
790 assert_field!(wtr, b("z"), out, 1, 1, InputEmpty, "z");
791 assert_write!(wtr, finish, out, 1, InputEmpty, "\"");
792 }
793
794 #[test]
795 fn writer_two_fields() {
796 let mut wtr = Writer::new();
797 let out = &mut [0; 1024];
798 let mut n = 0;
799
800 assert_field!(wtr, b("abc"), &mut out[n..], 3, 3, InputEmpty, "abc");
801 n += 3;
802 assert_write!(wtr, delimiter, &mut out[n..], 1, InputEmpty, ",");
803 n += 1;
804 assert_field!(wtr, b("yz"), &mut out[n..], 2, 2, InputEmpty, "yz");
805 n += 2;
806
807 assert_write!(wtr, finish, &mut out[n..], 0, InputEmpty, "");
808
809 assert_eq!("abc,yz", s(&out[..n]));
810 }
811
812 #[test]
813 fn writer_two_fields_non_numeric() {
814 let mut wtr =
815 WriterBuilder::new().quote_style(QuoteStyle::NonNumeric).build();
816 let out = &mut [0; 1024];
817 let mut n = 0;
818
819 assert_field!(wtr, b("abc"), &mut out[n..], 3, 4, InputEmpty, "\"abc");
820 n += 4;
821 assert_write!(wtr, delimiter, &mut out[n..], 2, InputEmpty, "\",");
822 n += 2;
823 assert_field!(wtr, b("5.2"), &mut out[n..], 3, 3, InputEmpty, "5.2");
824 n += 3;
825 assert_write!(wtr, delimiter, &mut out[n..], 1, InputEmpty, ",");
826 n += 1;
827 assert_field!(wtr, b("98"), &mut out[n..], 2, 2, InputEmpty, "98");
828 n += 2;
829
830 assert_write!(wtr, finish, &mut out[n..], 0, InputEmpty, "");
831
832 assert_eq!("\"abc\",5.2,98", s(&out[..n]));
833 }
834
835 #[test]
836 fn writer_two_fields_quote() {
837 let mut wtr = Writer::new();
838 let out = &mut [0; 1024];
839 let mut n = 0;
840
841 assert_field!(
842 wtr,
843 b("a,bc"),
844 &mut out[n..],
845 4,
846 5,
847 InputEmpty,
848 "\"a,bc"
849 );
850 n += 5;
851 assert_write!(wtr, delimiter, &mut out[n..], 2, InputEmpty, "\",");
852 n += 2;
853 assert_field!(wtr, b("\nz"), &mut out[n..], 2, 3, InputEmpty, "\"\nz");
854 n += 3;
855
856 assert_write!(wtr, finish, &mut out[n..], 1, InputEmpty, "\"");
857 n += 1;
858
859 assert_eq!("\"a,bc\",\"\nz\"", s(&out[..n]));
860 }
861
862 #[test]
863 fn writer_two_fields_two_records() {
864 let mut wtr = Writer::new();
865 let out = &mut [0; 1024];
866 let mut n = 0;
867
868 assert_field!(wtr, b("abc"), &mut out[n..], 3, 3, InputEmpty, "abc");
869 n += 3;
870 assert_write!(wtr, delimiter, &mut out[n..], 1, InputEmpty, ",");
871 n += 1;
872 assert_field!(wtr, b("yz"), &mut out[n..], 2, 2, InputEmpty, "yz");
873 n += 2;
874 assert_write!(wtr, terminator, &mut out[n..], 1, InputEmpty, "\n");
875 n += 1;
876 assert_field!(wtr, b("foo"), &mut out[n..], 3, 3, InputEmpty, "foo");
877 n += 3;
878 assert_write!(wtr, delimiter, &mut out[n..], 1, InputEmpty, ",");
879 n += 1;
880 assert_field!(wtr, b("quux"), &mut out[n..], 4, 4, InputEmpty, "quux");
881 n += 4;
882
883 assert_write!(wtr, finish, &mut out[n..], 0, InputEmpty, "");
884
885 assert_eq!("abc,yz\nfoo,quux", s(&out[..n]));
886 }
887
888 #[test]
889 fn writer_two_fields_two_records_quote() {
890 let mut wtr = Writer::new();
891 let out = &mut [0; 1024];
892 let mut n = 0;
893
894 assert_field!(
895 wtr,
896 b("a,bc"),
897 &mut out[n..],
898 4,
899 5,
900 InputEmpty,
901 "\"a,bc"
902 );
903 n += 5;
904 assert_write!(wtr, delimiter, &mut out[n..], 2, InputEmpty, "\",");
905 n += 2;
906 assert_field!(wtr, b("\nz"), &mut out[n..], 2, 3, InputEmpty, "\"\nz");
907 n += 3;
908 assert_write!(wtr, terminator, &mut out[n..], 2, InputEmpty, "\"\n");
909 n += 2;
910 assert_field!(
911 wtr,
912 b("f\"oo"),
913 &mut out[n..],
914 4,
915 6,
916 InputEmpty,
917 "\"f\"\"oo"
918 );
919 n += 6;
920 assert_write!(wtr, delimiter, &mut out[n..], 2, InputEmpty, "\",");
921 n += 2;
922 assert_field!(
923 wtr,
924 b("quux,"),
925 &mut out[n..],
926 5,
927 6,
928 InputEmpty,
929 "\"quux,"
930 );
931 n += 6;
932
933 assert_write!(wtr, finish, &mut out[n..], 1, InputEmpty, "\"");
934 n += 1;
935
936 assert_eq!("\"a,bc\",\"\nz\"\n\"f\"\"oo\",\"quux,\"", s(&out[..n]));
937 }
938
939 macro_rules! assert_quote {
940 (
941 $inp:expr, $out:expr,
942 $expect_in:expr, $expect_out:expr,
943 $expect_res:expr, $expect_data:expr
944 ) => {
945 assert_quote!(
946 $inp,
947 $out,
948 $expect_in,
949 $expect_out,
950 $expect_res,
951 $expect_data,
952 true
953 );
954 };
955 (
956 $inp:expr, $out:expr,
957 $expect_in:expr, $expect_out:expr,
958 $expect_res:expr, $expect_data:expr,
959 $double_quote:expr
960 ) => {{
961 let (res, i, o) = quote($inp, $out, b'"', b'\\', $double_quote);
962 assert_eq!($expect_res, res, "result");
963 assert_eq!($expect_in, i, "input");
964 assert_eq!($expect_out, o, "output");
965 assert_eq!(b($expect_data), &$out[..o], "data");
966 }};
967 }
968
969 #[test]
970 fn quote_empty() {
971 let inp = b("");
972 let out = &mut [0; 1024];
973
974 assert_quote!(inp, out, 0, 0, InputEmpty, "");
975 }
976
977 #[test]
978 fn quote_no_quotes() {
979 let inp = b("foobar");
980 let out = &mut [0; 1024];
981
982 assert_quote!(inp, out, 6, 6, InputEmpty, "foobar");
983 }
984
985 #[test]
986 fn quote_one_quote() {
987 let inp = b("\"");
988 let out = &mut [0; 1024];
989
990 assert_quote!(inp, out, 1, 2, InputEmpty, r#""""#);
991 }
992
993 #[test]
994 fn quote_two_quotes() {
995 let inp = b("\"\"");
996 let out = &mut [0; 1024];
997
998 assert_quote!(inp, out, 2, 4, InputEmpty, r#""""""#);
999 }
1000
1001 #[test]
1002 fn quote_escaped_one() {
1003 let inp = b("\"");
1004 let out = &mut [0; 1024];
1005
1006 assert_quote!(inp, out, 1, 2, InputEmpty, r#"\""#, false);
1007 }
1008
1009 #[test]
1010 fn quote_escaped_two() {
1011 let inp = b("\"\"");
1012 let out = &mut [0; 1024];
1013
1014 assert_quote!(inp, out, 2, 4, InputEmpty, r#"\"\""#, false);
1015 }
1016
1017 #[test]
1018 fn quote_misc() {
1019 let inp = b(r#"foo "bar" baz "quux"?"#);
1020 let out = &mut [0; 1024];
1021
1022 assert_quote!(
1023 inp,
1024 out,
1025 21,
1026 25,
1027 InputEmpty,
1028 r#"foo ""bar"" baz ""quux""?"#
1029 );
1030 }
1031
1032 #[test]
1033 fn quote_stream_no_quotes() {
1034 let mut inp = b("fooba");
1035 let out = &mut [0; 2];
1036
1037 assert_quote!(inp, out, 2, 2, OutputFull, "fo");
1038 inp = &inp[2..];
1039 assert_quote!(inp, out, 2, 2, OutputFull, "ob");
1040 inp = &inp[2..];
1041 assert_quote!(inp, out, 1, 1, InputEmpty, "a");
1042 }
1043
1044 #[test]
1045 fn quote_stream_quotes() {
1046 let mut inp = b(r#"a"bc"d""#);
1047 let out = &mut [0; 2];
1048
1049 assert_quote!(inp, out, 1, 1, OutputFull, "a");
1050 inp = &inp[1..];
1051 assert_quote!(inp, out, 1, 2, OutputFull, r#""""#);
1052 inp = &inp[1..];
1053 assert_quote!(inp, out, 2, 2, OutputFull, "bc");
1054 inp = &inp[2..];
1055 assert_quote!(inp, out, 1, 2, OutputFull, r#""""#);
1056 inp = &inp[1..];
1057 assert_quote!(inp, out, 1, 1, OutputFull, "d");
1058 inp = &inp[1..];
1059 assert_quote!(inp, out, 1, 2, InputEmpty, r#""""#);
1060 }
1061
1062 #[test]
1063 fn comment_char_is_automatically_quoted() {
1064 let mut wtr = WriterBuilder::new().comment(Some(b'#')).build();
1065 let out = &mut [0; 1024];
1066
1067 assert_field!(
1068 wtr,
1069 b("# abc"),
1070 &mut out[..],
1071 5,
1072 6,
1073 InputEmpty,
1074 "\"# abc"
1075 );
1076 assert_write!(wtr, finish, &mut out[..], 1, InputEmpty, "\"");
1077 }
1078}