• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use core::fmt;
2 use core::str;
3 
4 use memchr::memchr;
5 
6 use crate::{QuoteStyle, Terminator};
7 
8 /// A builder for configuring a CSV writer.
9 ///
10 /// This builder permits specifying the CSV delimiter, terminator, quoting
11 /// style and more.
12 #[derive(Debug)]
13 pub struct WriterBuilder {
14     wtr: Writer,
15 }
16 
17 impl WriterBuilder {
18     /// Create a new builder for configuring a CSV writer.
new() -> WriterBuilder19     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: wtr }
32     }
33 
34     /// Builder a CSV writer from this configuration.
build(&self) -> Writer35     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             // We only need to quote the escape character if the escape
43             // character is used for escaping quotes.
44             wtr.requires_quotes[self.wtr.escape as usize] = true;
45         }
46         match self.wtr.term {
47             CRLF | Any(b'\n') | Any(b'\r') => {
48                 // This is a bit hokey. By default, the record terminator
49                 // is '\n', but we still need to quote '\r' (even if our
50                 // terminator is only `\n`) because the reader interprets '\r'
51                 // as a record terminator by default.
52                 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             _ => unreachable!(),
59         }
60         // If the first field of a row starts with a comment character,
61         // it needs to be quoted, or the row will not be readable later.
62         // As requires_quotes is calculated in advance, we force quotes
63         // when a comment character is encountered anywhere in the field.
64         if let Some(comment) = self.wtr.comment {
65             wtr.requires_quotes[comment as usize] = true;
66         }
67         wtr
68     }
69 
70     /// The field delimiter to use when writing CSV.
71     ///
72     /// The default is `b','`.
delimiter(&mut self, delimiter: u8) -> &mut WriterBuilder73     pub fn delimiter(&mut self, delimiter: u8) -> &mut WriterBuilder {
74         self.wtr.delimiter = delimiter;
75         self
76     }
77 
78     /// The record terminator to use when writing CSV.
79     ///
80     /// A record terminator can be any single byte. The default is `\n`.
81     ///
82     /// Note that RFC 4180 specifies that record terminators should be `\r\n`.
83     /// To use `\r\n`, use the special `Terminator::CRLF` value.
terminator(&mut self, term: Terminator) -> &mut WriterBuilder84     pub fn terminator(&mut self, term: Terminator) -> &mut WriterBuilder {
85         self.wtr.term = term;
86         self
87     }
88 
89     /// The quoting style to use when writing CSV.
90     ///
91     /// By default, this is set to `QuoteStyle::Necessary`, which will only
92     /// use quotes when they are necessary to preserve the integrity of data.
93     ///
94     /// Note that unless the quote style is set to `Never`, an empty field is
95     /// quoted if it is the only field in a record.
quote_style(&mut self, style: QuoteStyle) -> &mut WriterBuilder96     pub fn quote_style(&mut self, style: QuoteStyle) -> &mut WriterBuilder {
97         self.wtr.style = style;
98         self
99     }
100 
101     /// The quote character to use when writing CSV.
102     ///
103     /// The default value is `b'"'`.
quote(&mut self, quote: u8) -> &mut WriterBuilder104     pub fn quote(&mut self, quote: u8) -> &mut WriterBuilder {
105         self.wtr.quote = quote;
106         self
107     }
108 
109     /// The escape character to use when writing CSV.
110     ///
111     /// This is only used when `double_quote` is set to `false`.
112     ///
113     /// The default value is `b'\\'`.
escape(&mut self, escape: u8) -> &mut WriterBuilder114     pub fn escape(&mut self, escape: u8) -> &mut WriterBuilder {
115         self.wtr.escape = escape;
116         self
117     }
118 
119     /// The quoting escape mechanism to use when writing CSV.
120     ///
121     /// When enabled (which is the default), quotes are escaped by doubling
122     /// them. e.g., `"` escapes to `""`.
123     ///
124     /// When disabled, quotes are escaped with the escape character (which
125     /// is `\\` by default).
double_quote(&mut self, yes: bool) -> &mut WriterBuilder126     pub fn double_quote(&mut self, yes: bool) -> &mut WriterBuilder {
127         self.wtr.double_quote = yes;
128         self
129     }
130 
131     /// The comment character that will be used when later reading the file.
132     ///
133     /// If `quote_style` is set to `QuoteStyle::Necessary`, a field will
134     /// be quoted if the comment character is detected anywhere in the field.
135     ///
136     /// The default value is None.
comment(&mut self, comment: Option<u8>) -> &mut WriterBuilder137     pub fn comment(&mut self, comment: Option<u8>) -> &mut WriterBuilder {
138         self.wtr.comment = comment;
139         self
140     }
141 }
142 
143 impl Default for WriterBuilder {
default() -> WriterBuilder144     fn default() -> WriterBuilder {
145         WriterBuilder::new()
146     }
147 }
148 
149 /// The result of writing CSV data.
150 ///
151 /// A value of this type is returned from every interaction with `Writer`. It
152 /// informs the caller how to proceed, namely, by indicating whether more
153 /// input should be given (`InputEmpty`) or if a bigger output buffer is needed
154 /// (`OutputFull`).
155 #[derive(Clone, Debug, Eq, PartialEq)]
156 pub enum WriteResult {
157     /// This result occurs when all of the bytes from the given input have
158     /// been processed.
159     InputEmpty,
160     /// This result occurs when the output buffer was too small to process
161     /// all of the input bytes. Generally, this means the caller must call
162     /// the corresponding method again with the rest of the input and more
163     /// room in the output buffer.
164     OutputFull,
165 }
166 
167 /// A writer for CSV data.
168 ///
169 /// # RFC 4180
170 ///
171 /// This writer conforms to RFC 4180 with one exception: it doesn't guarantee
172 /// that all records written are of the same length. Instead, the onus is on
173 /// the caller to ensure that all records written are of the same length.
174 ///
175 /// Note that the default configuration of a `Writer` uses `\n` for record
176 /// terminators instead of `\r\n` as specified by RFC 4180. Use the
177 /// `terminator` method on `WriterBuilder` to set the terminator to `\r\n` if
178 /// it's desired.
179 pub struct Writer {
180     state: WriterState,
181     requires_quotes: [bool; 256],
182     delimiter: u8,
183     term: Terminator,
184     style: QuoteStyle,
185     quote: u8,
186     escape: u8,
187     double_quote: bool,
188     comment: Option<u8>,
189 }
190 
191 impl Clone for Writer {
clone(&self) -> Writer192     fn clone(&self) -> Writer {
193         let mut requires_quotes = [false; 256];
194         for i in 0..256 {
195             requires_quotes[i] = self.requires_quotes[i];
196         }
197         Writer {
198             state: self.state.clone(),
199             requires_quotes: requires_quotes,
200             delimiter: self.delimiter,
201             term: self.term,
202             style: self.style,
203             quote: self.quote,
204             escape: self.escape,
205             double_quote: self.double_quote,
206             comment: self.comment,
207         }
208     }
209 }
210 
211 impl fmt::Debug for Writer {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result212     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
213         f.debug_struct("Writer")
214             .field("state", &self.state)
215             .field("delimiter", &self.delimiter)
216             .field("term", &self.term)
217             .field("style", &self.style)
218             .field("quote", &self.quote)
219             .field("escape", &self.escape)
220             .field("double_quote", &self.double_quote)
221             .finish()
222     }
223 }
224 
225 #[derive(Clone, Debug)]
226 struct WriterState {
227     /// This is set whenever we've begun writing the contents of a field, even
228     /// if the contents are empty. We use it to avoid re-computing whether
229     /// quotes are necessary.
230     in_field: bool,
231     /// This is set whenever we've started writing a field that is enclosed in
232     /// quotes. When the writer is finished, or if a delimiter or terminator
233     /// are written, then a closing quote is inserted when this is true.
234     quoting: bool,
235     /// The number of total bytes written for the current record.
236     ///
237     /// If the writer is finished or a terminator is written when this is `0`,
238     /// then an empty field is added as a pair of adjacent quotes.
239     record_bytes: u64,
240 }
241 
242 impl Writer {
243     /// Creates a new CSV writer with the default configuration.
new() -> Writer244     pub fn new() -> Writer {
245         Writer::default()
246     }
247 
248     /// Finish writing CSV data to `output`.
249     ///
250     /// This must be called when one is done writing CSV data to `output`.
251     /// In particular, it will write closing quotes if necessary.
finish(&mut self, mut output: &mut [u8]) -> (WriteResult, usize)252     pub fn finish(&mut self, mut output: &mut [u8]) -> (WriteResult, usize) {
253         let mut nout = 0;
254         if self.state.record_bytes == 0 && self.state.in_field {
255             assert!(!self.state.quoting);
256             let (res, o) = self.write(&[self.quote, self.quote], output);
257             if o == 0 {
258                 return (res, 0);
259             }
260             output = &mut moving(output)[o..];
261             nout += o;
262             self.state.record_bytes += o as u64;
263         }
264         if !self.state.quoting {
265             return (WriteResult::InputEmpty, nout);
266         }
267         let (res, o) = self.write(&[self.quote], output);
268         if o == 0 {
269             return (res, nout);
270         }
271         nout += o;
272         self.state.record_bytes = 0;
273         self.state.in_field = false;
274         self.state.quoting = false;
275         (res, nout)
276     }
277 
278     /// Write a single CSV field from `input` to `output` while employing this
279     /// writer's quoting style.
280     ///
281     /// This returns the result of writing field data, in addition to the
282     /// number of bytes consumed from `input` and the number of bytes
283     /// written to `output`.
284     ///
285     /// The result of writing field data is either `WriteResult::InputEmpty`
286     /// or `WriteResult::OutputFull`. The former occurs when all bytes in
287     /// `input` were copied to `output`, while the latter occurs when `output`
288     /// is too small to fit everything from `input`. The maximum number of
289     /// bytes that can be written to `output` is `2 + (2 * input.len())`
290     /// because of quoting. (The worst case is a field consisting entirely
291     /// of quotes.)
292     ///
293     /// Multiple successive calls to `field` will write more data to the same
294     /// field. Subsequent fields can be written by calling either `delimiter`
295     /// or `terminator` first.
296     ///
297     /// If this writer's quoting style is `QuoteStyle::Necessary`, then `input`
298     /// should contain the *entire* field. Otherwise, whether the field needs
299     /// to be quoted or not cannot be determined.
field( &mut self, input: &[u8], mut output: &mut [u8], ) -> (WriteResult, usize, usize)300     pub fn field(
301         &mut self,
302         input: &[u8],
303         mut output: &mut [u8],
304     ) -> (WriteResult, usize, usize) {
305         let (mut nin, mut nout) = (0, 0);
306 
307         if !self.state.in_field {
308             self.state.quoting = self.should_quote(input);
309             if self.state.quoting {
310                 let (res, o) = self.write(&[self.quote], output);
311                 if o == 0 {
312                     return (res, 0, 0);
313                 }
314                 output = &mut moving(output)[o..];
315                 nout += o;
316                 self.state.record_bytes += o as u64;
317             }
318             self.state.in_field = true;
319         }
320         let (res, i, o) = if self.state.quoting {
321             quote(input, output, self.quote, self.escape, self.double_quote)
322         } else {
323             write_optimistic(input, output)
324         };
325         nin += i;
326         nout += o;
327         self.state.record_bytes += o as u64;
328         (res, nin, nout)
329     }
330 
331     /// Write the configured field delimiter to `output`.
332     ///
333     /// If the output buffer does not have enough room to fit
334     /// a field delimiter, then nothing is written to `output`
335     /// and `WriteResult::OutputFull` is returned. Otherwise,
336     /// `WriteResult::InputEmpty` is returned along with the number of bytes
337     /// written to `output` (which is `1` in case of an unquoted
338     /// field, or `2` in case of an end quote and a field separator).
delimiter( &mut self, mut output: &mut [u8], ) -> (WriteResult, usize)339     pub fn delimiter(
340         &mut self,
341         mut output: &mut [u8],
342     ) -> (WriteResult, usize) {
343         let mut nout = 0;
344         if self.state.quoting {
345             let (res, o) = self.write(&[self.quote], output);
346             if o == 0 {
347                 return (res, o);
348             }
349             output = &mut moving(output)[o..];
350             nout += o;
351             self.state.record_bytes += o as u64;
352             self.state.quoting = false;
353         }
354         let (res, o) = self.write(&[self.delimiter], output);
355         if o == 0 {
356             return (res, nout);
357         }
358         nout += o;
359         self.state.record_bytes += o as u64;
360         self.state.in_field = false;
361         (res, nout)
362     }
363 
364     /// Write the configured record terminator to `output`.
365     ///
366     /// If the output buffer does not have enough room to fit a record
367     /// terminator, then no part of the terminator is written and
368     /// `WriteResult::OutputFull` is returned. Otherwise,
369     /// `WriteResult::InputEmpty` is returned along with the number of bytes
370     /// written to `output` (which is always `1` or `2`).
terminator( &mut self, mut output: &mut [u8], ) -> (WriteResult, usize)371     pub fn terminator(
372         &mut self,
373         mut output: &mut [u8],
374     ) -> (WriteResult, usize) {
375         let mut nout = 0;
376         if self.state.record_bytes == 0 {
377             assert!(!self.state.quoting);
378             let (res, o) = self.write(&[self.quote, self.quote], output);
379             if o == 0 {
380                 return (res, 0);
381             }
382             output = &mut moving(output)[o..];
383             nout += o;
384             self.state.record_bytes += o as u64;
385         }
386         if self.state.quoting {
387             let (res, o) = self.write(&[self.quote], output);
388             if o == 0 {
389                 return (res, o);
390             }
391             output = &mut moving(output)[o..];
392             nout += o;
393             self.state.record_bytes += o as u64;
394             self.state.quoting = false;
395         }
396         let (res, o) = match self.term {
397             Terminator::CRLF => write_pessimistic(&[b'\r', b'\n'], output),
398             Terminator::Any(b) => write_pessimistic(&[b], output),
399             _ => unreachable!(),
400         };
401         if o == 0 {
402             return (res, nout);
403         }
404         nout += o;
405         self.state.record_bytes = 0;
406         self.state.in_field = false;
407         (res, nout)
408     }
409 
410     /// Returns true if and only if the given input field *requires* quotes to
411     /// preserve the integrity of `input` while taking into account the current
412     /// configuration of this writer (except for the configured quoting style).
413     #[inline]
needs_quotes(&self, mut input: &[u8]) -> bool414     fn needs_quotes(&self, mut input: &[u8]) -> bool {
415         let mut needs = false;
416         while !needs && input.len() >= 8 {
417             needs = self.requires_quotes[input[0] as usize]
418                 || self.requires_quotes[input[1] as usize]
419                 || self.requires_quotes[input[2] as usize]
420                 || self.requires_quotes[input[3] as usize]
421                 || self.requires_quotes[input[4] as usize]
422                 || self.requires_quotes[input[5] as usize]
423                 || self.requires_quotes[input[6] as usize]
424                 || self.requires_quotes[input[7] as usize];
425             input = &input[8..];
426         }
427         needs || input.iter().any(|&b| self.is_special_byte(b))
428     }
429 
430     /// Returns true if and only if the given byte corresponds to a special
431     /// byte in this CSV writer's configuration.
432     ///
433     /// Note that this does **not** take into account this writer's quoting
434     /// style.
435     #[inline]
is_special_byte(&self, b: u8) -> bool436     pub fn is_special_byte(&self, b: u8) -> bool {
437         self.requires_quotes[b as usize]
438     }
439 
440     /// Returns true if and only if we should put the given field data
441     /// in quotes. This takes the quoting style into account.
442     #[inline]
should_quote(&self, input: &[u8]) -> bool443     pub fn should_quote(&self, input: &[u8]) -> bool {
444         match self.style {
445             QuoteStyle::Always => true,
446             QuoteStyle::Never => false,
447             QuoteStyle::NonNumeric => is_non_numeric(input),
448             QuoteStyle::Necessary => self.needs_quotes(input),
449             _ => unreachable!(),
450         }
451     }
452 
453     /// Return the delimiter used for this writer.
454     #[inline]
get_delimiter(&self) -> u8455     pub fn get_delimiter(&self) -> u8 {
456         self.delimiter
457     }
458 
459     /// Return the terminator used for this writer.
460     #[inline]
get_terminator(&self) -> Terminator461     pub fn get_terminator(&self) -> Terminator {
462         self.term
463     }
464 
465     /// Return the quoting style used for this writer.
466     #[inline]
get_quote_style(&self) -> QuoteStyle467     pub fn get_quote_style(&self) -> QuoteStyle {
468         self.style
469     }
470 
471     /// Return the quote character used for this writer.
472     #[inline]
get_quote(&self) -> u8473     pub fn get_quote(&self) -> u8 {
474         self.quote
475     }
476 
477     /// Return the escape character used for this writer.
478     #[inline]
get_escape(&self) -> u8479     pub fn get_escape(&self) -> u8 {
480         self.escape
481     }
482 
483     /// Return whether this writer doubles quotes or not. When the writer
484     /// does not double quotes, it will escape them using the escape character.
485     #[inline]
get_double_quote(&self) -> bool486     pub fn get_double_quote(&self) -> bool {
487         self.double_quote
488     }
489 
write(&self, data: &[u8], output: &mut [u8]) -> (WriteResult, usize)490     fn write(&self, data: &[u8], output: &mut [u8]) -> (WriteResult, usize) {
491         if data.len() > output.len() {
492             (WriteResult::OutputFull, 0)
493         } else {
494             output[..data.len()].copy_from_slice(data);
495             (WriteResult::InputEmpty, data.len())
496         }
497     }
498 }
499 
500 impl Default for Writer {
default() -> Writer501     fn default() -> Writer {
502         WriterBuilder::new().build()
503     }
504 }
505 
506 impl Default for WriterState {
default() -> WriterState507     fn default() -> WriterState {
508         WriterState { in_field: false, quoting: false, record_bytes: 0 }
509     }
510 }
511 
512 /// Returns true if and only if the given input is non-numeric.
is_non_numeric(input: &[u8]) -> bool513 pub fn is_non_numeric(input: &[u8]) -> bool {
514     let s = match str::from_utf8(input) {
515         Err(_) => return true,
516         Ok(s) => s,
517     };
518     // I suppose this could be faster if we wrote validators of numbers instead
519     // of using the actual parser, but that's probably a lot of work for a bit
520     // of a niche feature.
521     !s.parse::<f64>().is_ok() && !s.parse::<i128>().is_ok()
522 }
523 
524 /// Escape quotes `input` and writes the result to `output`.
525 ///
526 /// If `input` does not have a `quote`, then the contents of `input` are
527 /// copied verbatim to `output`.
528 ///
529 /// If `output` is not big enough to store the fully quoted contents of
530 /// `input`, then `WriteResult::OutputFull` is returned. The `output` buffer
531 /// will require a maximum of storage of `2 * input.len()` in the worst case
532 /// (where every byte is a quote).
533 ///
534 /// In streaming contexts, `quote` should be called in a loop until
535 /// `WriteResult::InputEmpty` is returned. It is possible to write an infinite
536 /// loop if your output buffer is less than 2 bytes in length (the minimum
537 /// storage space required to store an escaped quote).
538 ///
539 /// In addition to the `WriteResult`, the number of consumed bytes from `input`
540 /// and the number of bytes written to `output` are also returned.
541 ///
542 /// `quote` is the quote byte and `escape` is the escape byte. If
543 /// `double_quote` is true, then quotes are escaped by doubling them,
544 /// otherwise, quotes are escaped with the `escape` byte.
545 ///
546 /// N.B. This function is provided for low level usage. It is called
547 /// automatically if you're using a `Writer`.
quote( mut input: &[u8], mut output: &mut [u8], quote: u8, escape: u8, double_quote: bool, ) -> (WriteResult, usize, usize)548 pub fn quote(
549     mut input: &[u8],
550     mut output: &mut [u8],
551     quote: u8,
552     escape: u8,
553     double_quote: bool,
554 ) -> (WriteResult, usize, usize) {
555     let (mut nin, mut nout) = (0, 0);
556     loop {
557         match memchr(quote, input) {
558             None => {
559                 let (res, i, o) = write_optimistic(input, output);
560                 nin += i;
561                 nout += o;
562                 return (res, nin, nout);
563             }
564             Some(next_quote) => {
565                 let (res, i, o) =
566                     write_optimistic(&input[..next_quote], output);
567                 input = &input[i..];
568                 output = &mut moving(output)[o..];
569                 nin += i;
570                 nout += o;
571                 if let WriteResult::OutputFull = res {
572                     return (res, nin, nout);
573                 }
574                 if double_quote {
575                     let (res, o) = write_pessimistic(&[quote, quote], output);
576                     if let WriteResult::OutputFull = res {
577                         return (res, nin, nout);
578                     }
579                     nout += o;
580                     output = &mut moving(output)[o..];
581                 } else {
582                     let (res, o) = write_pessimistic(&[escape, quote], output);
583                     if let WriteResult::OutputFull = res {
584                         return (res, nin, nout);
585                     }
586                     nout += o;
587                     output = &mut moving(output)[o..];
588                 }
589                 nin += 1;
590                 input = &input[1..];
591             }
592         }
593     }
594 }
595 
596 /// Copy the bytes from `input` to `output`. If `output` is too small to fit
597 /// everything from `input`, then copy `output.len()` bytes from `input`.
598 /// Otherwise, copy everything from `input` into `output`.
599 ///
600 /// In the first case (`output` is too small), `WriteResult::OutputFull` is
601 /// returned, in addition to the number of bytes consumed from `input` and
602 /// the number of bytes written to `output`.
603 ///
604 /// In the second case (`input` is no bigger than `output`),
605 /// `WriteResult::InputEmpty` is returned, in addition to the number of bytes
606 /// consumed from `input` and the number of bytes written to `output`.
write_optimistic( input: &[u8], output: &mut [u8], ) -> (WriteResult, usize, usize)607 fn write_optimistic(
608     input: &[u8],
609     output: &mut [u8],
610 ) -> (WriteResult, usize, usize) {
611     if input.len() > output.len() {
612         let input = &input[..output.len()];
613         output.copy_from_slice(input);
614         (WriteResult::OutputFull, output.len(), output.len())
615     } else {
616         output[..input.len()].copy_from_slice(input);
617         (WriteResult::InputEmpty, input.len(), input.len())
618     }
619 }
620 
621 /// Copy the bytes from `input` to `output` only if `input` is no bigger than
622 /// `output`. If `input` is bigger than `output`, then return
623 /// `WriteResult::OutputFull` and copy nothing into `output`. Otherwise,
624 /// return `WriteResult::InputEmpty` and the number of bytes copied into
625 /// `output`.
write_pessimistic(input: &[u8], output: &mut [u8]) -> (WriteResult, usize)626 fn write_pessimistic(input: &[u8], output: &mut [u8]) -> (WriteResult, usize) {
627     if input.len() > output.len() {
628         (WriteResult::OutputFull, 0)
629     } else {
630         output[..input.len()].copy_from_slice(input);
631         (WriteResult::InputEmpty, input.len())
632     }
633 }
634 
635 /// This avoids reborrowing.
636 /// See: https://bluss.github.io/rust/fun/2015/10/11/stuff-the-identity-function-does/
moving<T>(x: T) -> T637 fn moving<T>(x: T) -> T {
638     x
639 }
640 
641 #[cfg(test)]
642 mod tests {
643     use crate::writer::WriteResult::*;
644     use crate::writer::{quote, QuoteStyle, Writer, WriterBuilder};
645 
646     // OMG I HATE BYTE STRING LITERALS SO MUCH.
b(s: &str) -> &[u8]647     fn b(s: &str) -> &[u8] {
648         s.as_bytes()
649     }
s(b: &[u8]) -> &str650     fn s(b: &[u8]) -> &str {
651         ::core::str::from_utf8(b).unwrap()
652     }
653 
654     macro_rules! assert_field {
655         (
656             $wtr:expr, $inp:expr, $out:expr,
657             $expect_in:expr, $expect_out:expr,
658             $expect_res:expr, $expect_data:expr
659         ) => {{
660             let (res, i, o) = $wtr.field($inp, $out);
661             assert_eq!($expect_res, res, "result");
662             assert_eq!($expect_in, i, "input");
663             assert_eq!($expect_out, o, "output");
664             assert_eq!($expect_data, s(&$out[..o]), "data");
665         }};
666     }
667 
668     macro_rules! assert_write {
669         (
670             $wtr:expr, $which:ident, $out:expr,
671             $expect_out:expr, $expect_res:expr, $expect_data:expr
672         ) => {{
673             let (res, o) = $wtr.$which($out);
674             assert_eq!($expect_res, res, "result");
675             assert_eq!($expect_out, o, "output");
676             assert_eq!($expect_data, s(&$out[..o]), "data");
677         }};
678     }
679 
680     #[test]
writer_one_field()681     fn writer_one_field() {
682         let mut wtr = Writer::new();
683         let out = &mut [0; 1024];
684         let mut n = 0;
685 
686         assert_field!(wtr, b("abc"), &mut out[n..], 3, 3, InputEmpty, "abc");
687         n += 3;
688 
689         assert_write!(wtr, finish, &mut out[n..], 0, InputEmpty, "");
690     }
691 
692     #[test]
writer_one_empty_field_terminator()693     fn writer_one_empty_field_terminator() {
694         let mut wtr = Writer::new();
695         let out = &mut [0; 1024];
696 
697         assert_field!(wtr, b(""), &mut out[..], 0, 0, InputEmpty, "");
698         assert_write!(wtr, terminator, &mut out[..], 3, InputEmpty, "\"\"\n");
699         assert_write!(wtr, finish, &mut out[..], 0, InputEmpty, "");
700     }
701 
702     #[test]
writer_one_empty_field_finish()703     fn writer_one_empty_field_finish() {
704         let mut wtr = Writer::new();
705         let out = &mut [0; 1024];
706 
707         assert_field!(wtr, b(""), &mut out[..], 0, 0, InputEmpty, "");
708         assert_write!(wtr, finish, &mut out[..], 2, InputEmpty, "\"\"");
709     }
710 
711     #[test]
writer_many_one_empty_field_finish()712     fn writer_many_one_empty_field_finish() {
713         let mut wtr = Writer::new();
714         let out = &mut [0; 1024];
715 
716         assert_field!(wtr, b(""), &mut out[..], 0, 0, InputEmpty, "");
717         assert_write!(wtr, terminator, &mut out[..], 3, InputEmpty, "\"\"\n");
718         assert_field!(wtr, b(""), &mut out[..], 0, 0, InputEmpty, "");
719         assert_write!(wtr, finish, &mut out[..], 2, InputEmpty, "\"\"");
720     }
721 
722     #[test]
writer_many_one_empty_field_terminator()723     fn writer_many_one_empty_field_terminator() {
724         let mut wtr = Writer::new();
725         let out = &mut [0; 1024];
726 
727         assert_field!(wtr, b(""), &mut out[..], 0, 0, InputEmpty, "");
728         assert_write!(wtr, terminator, &mut out[..], 3, InputEmpty, "\"\"\n");
729         assert_field!(wtr, b(""), &mut out[..], 0, 0, InputEmpty, "");
730         assert_write!(wtr, terminator, &mut out[..], 3, InputEmpty, "\"\"\n");
731         assert_write!(wtr, finish, &mut out[..], 0, InputEmpty, "");
732     }
733 
734     #[test]
writer_one_field_quote()735     fn writer_one_field_quote() {
736         let mut wtr = Writer::new();
737         let out = &mut [0; 1024];
738         let mut n = 0;
739 
740         assert_field!(
741             wtr,
742             b("a\"bc"),
743             &mut out[n..],
744             4,
745             6,
746             InputEmpty,
747             "\"a\"\"bc"
748         );
749         n += 6;
750 
751         assert_write!(wtr, finish, &mut out[n..], 1, InputEmpty, "\"");
752     }
753 
754     #[test]
writer_one_field_stream()755     fn writer_one_field_stream() {
756         let mut wtr = Writer::new();
757         let out = &mut [0; 1024];
758         let mut n = 0;
759 
760         assert_field!(wtr, b("abc"), &mut out[n..], 3, 3, InputEmpty, "abc");
761         n += 3;
762         assert_field!(wtr, b("x"), &mut out[n..], 1, 1, InputEmpty, "x");
763         n += 1;
764 
765         assert_write!(wtr, finish, &mut out[n..], 0, InputEmpty, "");
766     }
767 
768     #[test]
writer_one_field_stream_quote()769     fn writer_one_field_stream_quote() {
770         let mut wtr = Writer::new();
771         let out = &mut [0; 1024];
772         let mut n = 0;
773 
774         assert_field!(
775             wtr,
776             b("abc\""),
777             &mut out[n..],
778             4,
779             6,
780             InputEmpty,
781             "\"abc\"\""
782         );
783         n += 6;
784         assert_field!(wtr, b("x"), &mut out[n..], 1, 1, InputEmpty, "x");
785         n += 1;
786 
787         assert_write!(wtr, finish, &mut out[n..], 1, InputEmpty, "\"");
788     }
789 
790     #[test]
writer_one_field_stream_quote_partial()791     fn writer_one_field_stream_quote_partial() {
792         let mut wtr = Writer::new();
793         let out = &mut [0; 4];
794 
795         assert_field!(wtr, b("ab\"xyz"), out, 2, 3, OutputFull, "\"ab");
796         assert_field!(wtr, b("\"xyz"), out, 3, 4, OutputFull, "\"\"xy");
797         assert_field!(wtr, b("z"), out, 1, 1, InputEmpty, "z");
798         assert_write!(wtr, finish, out, 1, InputEmpty, "\"");
799     }
800 
801     #[test]
writer_two_fields()802     fn writer_two_fields() {
803         let mut wtr = Writer::new();
804         let out = &mut [0; 1024];
805         let mut n = 0;
806 
807         assert_field!(wtr, b("abc"), &mut out[n..], 3, 3, InputEmpty, "abc");
808         n += 3;
809         assert_write!(wtr, delimiter, &mut out[n..], 1, InputEmpty, ",");
810         n += 1;
811         assert_field!(wtr, b("yz"), &mut out[n..], 2, 2, InputEmpty, "yz");
812         n += 2;
813 
814         assert_write!(wtr, finish, &mut out[n..], 0, InputEmpty, "");
815 
816         assert_eq!("abc,yz", s(&out[..n]));
817     }
818 
819     #[test]
writer_two_fields_non_numeric()820     fn writer_two_fields_non_numeric() {
821         let mut wtr =
822             WriterBuilder::new().quote_style(QuoteStyle::NonNumeric).build();
823         let out = &mut [0; 1024];
824         let mut n = 0;
825 
826         assert_field!(wtr, b("abc"), &mut out[n..], 3, 4, InputEmpty, "\"abc");
827         n += 4;
828         assert_write!(wtr, delimiter, &mut out[n..], 2, InputEmpty, "\",");
829         n += 2;
830         assert_field!(wtr, b("5.2"), &mut out[n..], 3, 3, InputEmpty, "5.2");
831         n += 3;
832         assert_write!(wtr, delimiter, &mut out[n..], 1, InputEmpty, ",");
833         n += 1;
834         assert_field!(wtr, b("98"), &mut out[n..], 2, 2, InputEmpty, "98");
835         n += 2;
836 
837         assert_write!(wtr, finish, &mut out[n..], 0, InputEmpty, "");
838 
839         assert_eq!("\"abc\",5.2,98", s(&out[..n]));
840     }
841 
842     #[test]
writer_two_fields_quote()843     fn writer_two_fields_quote() {
844         let mut wtr = Writer::new();
845         let out = &mut [0; 1024];
846         let mut n = 0;
847 
848         assert_field!(
849             wtr,
850             b("a,bc"),
851             &mut out[n..],
852             4,
853             5,
854             InputEmpty,
855             "\"a,bc"
856         );
857         n += 5;
858         assert_write!(wtr, delimiter, &mut out[n..], 2, InputEmpty, "\",");
859         n += 2;
860         assert_field!(wtr, b("\nz"), &mut out[n..], 2, 3, InputEmpty, "\"\nz");
861         n += 3;
862 
863         assert_write!(wtr, finish, &mut out[n..], 1, InputEmpty, "\"");
864         n += 1;
865 
866         assert_eq!("\"a,bc\",\"\nz\"", s(&out[..n]));
867     }
868 
869     #[test]
writer_two_fields_two_records()870     fn writer_two_fields_two_records() {
871         let mut wtr = Writer::new();
872         let out = &mut [0; 1024];
873         let mut n = 0;
874 
875         assert_field!(wtr, b("abc"), &mut out[n..], 3, 3, InputEmpty, "abc");
876         n += 3;
877         assert_write!(wtr, delimiter, &mut out[n..], 1, InputEmpty, ",");
878         n += 1;
879         assert_field!(wtr, b("yz"), &mut out[n..], 2, 2, InputEmpty, "yz");
880         n += 2;
881         assert_write!(wtr, terminator, &mut out[n..], 1, InputEmpty, "\n");
882         n += 1;
883         assert_field!(wtr, b("foo"), &mut out[n..], 3, 3, InputEmpty, "foo");
884         n += 3;
885         assert_write!(wtr, delimiter, &mut out[n..], 1, InputEmpty, ",");
886         n += 1;
887         assert_field!(wtr, b("quux"), &mut out[n..], 4, 4, InputEmpty, "quux");
888         n += 4;
889 
890         assert_write!(wtr, finish, &mut out[n..], 0, InputEmpty, "");
891 
892         assert_eq!("abc,yz\nfoo,quux", s(&out[..n]));
893     }
894 
895     #[test]
writer_two_fields_two_records_quote()896     fn writer_two_fields_two_records_quote() {
897         let mut wtr = Writer::new();
898         let out = &mut [0; 1024];
899         let mut n = 0;
900 
901         assert_field!(
902             wtr,
903             b("a,bc"),
904             &mut out[n..],
905             4,
906             5,
907             InputEmpty,
908             "\"a,bc"
909         );
910         n += 5;
911         assert_write!(wtr, delimiter, &mut out[n..], 2, InputEmpty, "\",");
912         n += 2;
913         assert_field!(wtr, b("\nz"), &mut out[n..], 2, 3, InputEmpty, "\"\nz");
914         n += 3;
915         assert_write!(wtr, terminator, &mut out[n..], 2, InputEmpty, "\"\n");
916         n += 2;
917         assert_field!(
918             wtr,
919             b("f\"oo"),
920             &mut out[n..],
921             4,
922             6,
923             InputEmpty,
924             "\"f\"\"oo"
925         );
926         n += 6;
927         assert_write!(wtr, delimiter, &mut out[n..], 2, InputEmpty, "\",");
928         n += 2;
929         assert_field!(
930             wtr,
931             b("quux,"),
932             &mut out[n..],
933             5,
934             6,
935             InputEmpty,
936             "\"quux,"
937         );
938         n += 6;
939 
940         assert_write!(wtr, finish, &mut out[n..], 1, InputEmpty, "\"");
941         n += 1;
942 
943         assert_eq!("\"a,bc\",\"\nz\"\n\"f\"\"oo\",\"quux,\"", s(&out[..n]));
944     }
945 
946     macro_rules! assert_quote {
947         (
948             $inp:expr, $out:expr,
949             $expect_in:expr, $expect_out:expr,
950             $expect_res:expr, $expect_data:expr
951         ) => {
952             assert_quote!(
953                 $inp,
954                 $out,
955                 $expect_in,
956                 $expect_out,
957                 $expect_res,
958                 $expect_data,
959                 true
960             );
961         };
962         (
963             $inp:expr, $out:expr,
964             $expect_in:expr, $expect_out:expr,
965             $expect_res:expr, $expect_data:expr,
966             $double_quote:expr
967         ) => {{
968             let (res, i, o) = quote($inp, $out, b'"', b'\\', $double_quote);
969             assert_eq!($expect_res, res, "result");
970             assert_eq!($expect_in, i, "input");
971             assert_eq!($expect_out, o, "output");
972             assert_eq!(b($expect_data), &$out[..o], "data");
973         }};
974     }
975 
976     #[test]
quote_empty()977     fn quote_empty() {
978         let inp = b("");
979         let out = &mut [0; 1024];
980 
981         assert_quote!(inp, out, 0, 0, InputEmpty, "");
982     }
983 
984     #[test]
quote_no_quotes()985     fn quote_no_quotes() {
986         let inp = b("foobar");
987         let out = &mut [0; 1024];
988 
989         assert_quote!(inp, out, 6, 6, InputEmpty, "foobar");
990     }
991 
992     #[test]
quote_one_quote()993     fn quote_one_quote() {
994         let inp = b("\"");
995         let out = &mut [0; 1024];
996 
997         assert_quote!(inp, out, 1, 2, InputEmpty, r#""""#);
998     }
999 
1000     #[test]
quote_two_quotes()1001     fn quote_two_quotes() {
1002         let inp = b("\"\"");
1003         let out = &mut [0; 1024];
1004 
1005         assert_quote!(inp, out, 2, 4, InputEmpty, r#""""""#);
1006     }
1007 
1008     #[test]
quote_escaped_one()1009     fn quote_escaped_one() {
1010         let inp = b("\"");
1011         let out = &mut [0; 1024];
1012 
1013         assert_quote!(inp, out, 1, 2, InputEmpty, r#"\""#, false);
1014     }
1015 
1016     #[test]
quote_escaped_two()1017     fn quote_escaped_two() {
1018         let inp = b("\"\"");
1019         let out = &mut [0; 1024];
1020 
1021         assert_quote!(inp, out, 2, 4, InputEmpty, r#"\"\""#, false);
1022     }
1023 
1024     #[test]
quote_misc()1025     fn quote_misc() {
1026         let inp = b(r#"foo "bar" baz "quux"?"#);
1027         let out = &mut [0; 1024];
1028 
1029         assert_quote!(
1030             inp,
1031             out,
1032             21,
1033             25,
1034             InputEmpty,
1035             r#"foo ""bar"" baz ""quux""?"#
1036         );
1037     }
1038 
1039     #[test]
quote_stream_no_quotes()1040     fn quote_stream_no_quotes() {
1041         let mut inp = b("fooba");
1042         let out = &mut [0; 2];
1043 
1044         assert_quote!(inp, out, 2, 2, OutputFull, "fo");
1045         inp = &inp[2..];
1046         assert_quote!(inp, out, 2, 2, OutputFull, "ob");
1047         inp = &inp[2..];
1048         assert_quote!(inp, out, 1, 1, InputEmpty, "a");
1049     }
1050 
1051     #[test]
quote_stream_quotes()1052     fn quote_stream_quotes() {
1053         let mut inp = b(r#"a"bc"d""#);
1054         let out = &mut [0; 2];
1055 
1056         assert_quote!(inp, out, 1, 1, OutputFull, "a");
1057         inp = &inp[1..];
1058         assert_quote!(inp, out, 1, 2, OutputFull, r#""""#);
1059         inp = &inp[1..];
1060         assert_quote!(inp, out, 2, 2, OutputFull, "bc");
1061         inp = &inp[2..];
1062         assert_quote!(inp, out, 1, 2, OutputFull, r#""""#);
1063         inp = &inp[1..];
1064         assert_quote!(inp, out, 1, 1, OutputFull, "d");
1065         inp = &inp[1..];
1066         assert_quote!(inp, out, 1, 2, InputEmpty, r#""""#);
1067     }
1068 
1069     #[test]
comment_char_is_automatically_quoted()1070     fn comment_char_is_automatically_quoted() {
1071         let mut wtr = WriterBuilder::new().comment(Some(b'#')).build();
1072         let out = &mut [0; 1024];
1073 
1074         assert_field!(
1075             wtr,
1076             b("# abc"),
1077             &mut out[..],
1078             5,
1079             6,
1080             InputEmpty,
1081             "\"# abc"
1082         );
1083         assert_write!(wtr, finish, &mut out[..], 1, InputEmpty, "\"");
1084     }
1085 }
1086