1 use std::{fs::File, io, path::Path, result};
2 
3 use {
4     csv_core::{
5         self, WriteResult, Writer as CoreWriter,
6         WriterBuilder as CoreWriterBuilder,
7     },
8     serde::Serialize,
9 };
10 
11 use crate::{
12     byte_record::ByteRecord,
13     error::{Error, ErrorKind, IntoInnerError, Result},
14     serializer::{serialize, serialize_header},
15     {QuoteStyle, Terminator},
16 };
17 
18 /// Builds a CSV writer with various configuration knobs.
19 ///
20 /// This builder can be used to tweak the field delimiter, record terminator
21 /// and more. Once a CSV `Writer` is built, its configuration cannot be
22 /// changed.
23 #[derive(Debug)]
24 pub struct WriterBuilder {
25     builder: CoreWriterBuilder,
26     capacity: usize,
27     flexible: bool,
28     has_headers: bool,
29 }
30 
31 impl Default for WriterBuilder {
default() -> WriterBuilder32     fn default() -> WriterBuilder {
33         WriterBuilder {
34             builder: CoreWriterBuilder::default(),
35             capacity: 8 * (1 << 10),
36             flexible: false,
37             has_headers: true,
38         }
39     }
40 }
41 
42 impl WriterBuilder {
43     /// Create a new builder for configuring CSV writing.
44     ///
45     /// To convert a builder into a writer, call one of the methods starting
46     /// with `from_`.
47     ///
48     /// # Example
49     ///
50     /// ```
51     /// use std::error::Error;
52     /// use csv::WriterBuilder;
53     ///
54     /// # fn main() { example().unwrap(); }
55     /// fn example() -> Result<(), Box<dyn Error>> {
56     ///     let mut wtr = WriterBuilder::new().from_writer(vec![]);
57     ///     wtr.write_record(&["a", "b", "c"])?;
58     ///     wtr.write_record(&["x", "y", "z"])?;
59     ///
60     ///     let data = String::from_utf8(wtr.into_inner()?)?;
61     ///     assert_eq!(data, "a,b,c\nx,y,z\n");
62     ///     Ok(())
63     /// }
64     /// ```
new() -> WriterBuilder65     pub fn new() -> WriterBuilder {
66         WriterBuilder::default()
67     }
68 
69     /// Build a CSV writer from this configuration that writes data to the
70     /// given file path. The file is truncated if it already exists.
71     ///
72     /// If there was a problem opening the file at the given path, then this
73     /// returns the corresponding error.
74     ///
75     /// # Example
76     ///
77     /// ```no_run
78     /// use std::error::Error;
79     /// use csv::WriterBuilder;
80     ///
81     /// # fn main() { example().unwrap(); }
82     /// fn example() -> Result<(), Box<dyn Error>> {
83     ///     let mut wtr = WriterBuilder::new().from_path("foo.csv")?;
84     ///     wtr.write_record(&["a", "b", "c"])?;
85     ///     wtr.write_record(&["x", "y", "z"])?;
86     ///     wtr.flush()?;
87     ///     Ok(())
88     /// }
89     /// ```
from_path<P: AsRef<Path>>(&self, path: P) -> Result<Writer<File>>90     pub fn from_path<P: AsRef<Path>>(&self, path: P) -> Result<Writer<File>> {
91         Ok(Writer::new(self, File::create(path)?))
92     }
93 
94     /// Build a CSV writer from this configuration that writes data to `wtr`.
95     ///
96     /// Note that the CSV writer is buffered automatically, so you should not
97     /// wrap `wtr` in a buffered writer like `io::BufWriter`.
98     ///
99     /// # Example
100     ///
101     /// ```
102     /// use std::error::Error;
103     /// use csv::WriterBuilder;
104     ///
105     /// # fn main() { example().unwrap(); }
106     /// fn example() -> Result<(), Box<dyn Error>> {
107     ///     let mut wtr = WriterBuilder::new().from_writer(vec![]);
108     ///     wtr.write_record(&["a", "b", "c"])?;
109     ///     wtr.write_record(&["x", "y", "z"])?;
110     ///
111     ///     let data = String::from_utf8(wtr.into_inner()?)?;
112     ///     assert_eq!(data, "a,b,c\nx,y,z\n");
113     ///     Ok(())
114     /// }
115     /// ```
from_writer<W: io::Write>(&self, wtr: W) -> Writer<W>116     pub fn from_writer<W: io::Write>(&self, wtr: W) -> Writer<W> {
117         Writer::new(self, wtr)
118     }
119 
120     /// The field delimiter to use when writing CSV.
121     ///
122     /// The default is `b','`.
123     ///
124     /// # Example
125     ///
126     /// ```
127     /// use std::error::Error;
128     /// use csv::WriterBuilder;
129     ///
130     /// # fn main() { example().unwrap(); }
131     /// fn example() -> Result<(), Box<dyn Error>> {
132     ///     let mut wtr = WriterBuilder::new()
133     ///         .delimiter(b';')
134     ///         .from_writer(vec![]);
135     ///     wtr.write_record(&["a", "b", "c"])?;
136     ///     wtr.write_record(&["x", "y", "z"])?;
137     ///
138     ///     let data = String::from_utf8(wtr.into_inner()?)?;
139     ///     assert_eq!(data, "a;b;c\nx;y;z\n");
140     ///     Ok(())
141     /// }
142     /// ```
delimiter(&mut self, delimiter: u8) -> &mut WriterBuilder143     pub fn delimiter(&mut self, delimiter: u8) -> &mut WriterBuilder {
144         self.builder.delimiter(delimiter);
145         self
146     }
147 
148     /// Whether to write a header row before writing any other row.
149     ///
150     /// When this is enabled and the `serialize` method is used to write data
151     /// with something that contains field names (i.e., a struct), then a
152     /// header row is written containing the field names before any other row
153     /// is written.
154     ///
155     /// This option has no effect when using other methods to write rows. That
156     /// is, if you don't use `serialize`, then you must write your header row
157     /// explicitly if you want a header row.
158     ///
159     /// This is enabled by default.
160     ///
161     /// # Example: with headers
162     ///
163     /// This shows how the header will be automatically written from the field
164     /// names of a struct.
165     ///
166     /// ```
167     /// use std::error::Error;
168     ///
169     /// use csv::WriterBuilder;
170     ///
171     /// #[derive(serde::Serialize)]
172     /// struct Row<'a> {
173     ///     city: &'a str,
174     ///     country: &'a str,
175     ///     // Serde allows us to name our headers exactly,
176     ///     // even if they don't match our struct field names.
177     ///     #[serde(rename = "popcount")]
178     ///     population: u64,
179     /// }
180     ///
181     /// # fn main() { example().unwrap(); }
182     /// fn example() -> Result<(), Box<dyn Error>> {
183     ///     let mut wtr = WriterBuilder::new().from_writer(vec![]);
184     ///     wtr.serialize(Row {
185     ///         city: "Boston",
186     ///         country: "United States",
187     ///         population: 4628910,
188     ///     })?;
189     ///     wtr.serialize(Row {
190     ///         city: "Concord",
191     ///         country: "United States",
192     ///         population: 42695,
193     ///     })?;
194     ///
195     ///     let data = String::from_utf8(wtr.into_inner()?)?;
196     ///     assert_eq!(data, "\
197     /// city,country,popcount
198     /// Boston,United States,4628910
199     /// Concord,United States,42695
200     /// ");
201     ///     Ok(())
202     /// }
203     /// ```
204     ///
205     /// # Example: without headers
206     ///
207     /// This shows that serializing things that aren't structs (in this case,
208     /// a tuple struct) won't result in a header row being written. This means
209     /// you usually don't need to set `has_headers(false)` unless you
210     /// explicitly want to both write custom headers and serialize structs.
211     ///
212     /// ```
213     /// use std::error::Error;
214     /// use csv::WriterBuilder;
215     ///
216     /// # fn main() { example().unwrap(); }
217     /// fn example() -> Result<(), Box<dyn Error>> {
218     ///     let mut wtr = WriterBuilder::new().from_writer(vec![]);
219     ///     wtr.serialize(("Boston", "United States", 4628910))?;
220     ///     wtr.serialize(("Concord", "United States", 42695))?;
221     ///
222     ///     let data = String::from_utf8(wtr.into_inner()?)?;
223     ///     assert_eq!(data, "\
224     /// Boston,United States,4628910
225     /// Concord,United States,42695
226     /// ");
227     ///     Ok(())
228     /// }
229     /// ```
has_headers(&mut self, yes: bool) -> &mut WriterBuilder230     pub fn has_headers(&mut self, yes: bool) -> &mut WriterBuilder {
231         self.has_headers = yes;
232         self
233     }
234 
235     /// Whether the number of fields in records is allowed to change or not.
236     ///
237     /// When disabled (which is the default), writing CSV data will return an
238     /// error if a record is written with a number of fields different from the
239     /// number of fields written in a previous record.
240     ///
241     /// When enabled, this error checking is turned off.
242     ///
243     /// # Example: writing flexible records
244     ///
245     /// ```
246     /// use std::error::Error;
247     /// use csv::WriterBuilder;
248     ///
249     /// # fn main() { example().unwrap(); }
250     /// fn example() -> Result<(), Box<dyn Error>> {
251     ///     let mut wtr = WriterBuilder::new()
252     ///         .flexible(true)
253     ///         .from_writer(vec![]);
254     ///     wtr.write_record(&["a", "b"])?;
255     ///     wtr.write_record(&["x", "y", "z"])?;
256     ///
257     ///     let data = String::from_utf8(wtr.into_inner()?)?;
258     ///     assert_eq!(data, "a,b\nx,y,z\n");
259     ///     Ok(())
260     /// }
261     /// ```
262     ///
263     /// # Example: error when `flexible` is disabled
264     ///
265     /// ```
266     /// use std::error::Error;
267     /// use csv::WriterBuilder;
268     ///
269     /// # fn main() { example().unwrap(); }
270     /// fn example() -> Result<(), Box<dyn Error>> {
271     ///     let mut wtr = WriterBuilder::new()
272     ///         .flexible(false)
273     ///         .from_writer(vec![]);
274     ///     wtr.write_record(&["a", "b"])?;
275     ///     let err = wtr.write_record(&["x", "y", "z"]).unwrap_err();
276     ///     match *err.kind() {
277     ///         csv::ErrorKind::UnequalLengths { expected_len, len, .. } => {
278     ///             assert_eq!(expected_len, 2);
279     ///             assert_eq!(len, 3);
280     ///         }
281     ///         ref wrong => {
282     ///             panic!("expected UnequalLengths but got {:?}", wrong);
283     ///         }
284     ///     }
285     ///     Ok(())
286     /// }
287     /// ```
flexible(&mut self, yes: bool) -> &mut WriterBuilder288     pub fn flexible(&mut self, yes: bool) -> &mut WriterBuilder {
289         self.flexible = yes;
290         self
291     }
292 
293     /// The record terminator to use when writing CSV.
294     ///
295     /// A record terminator can be any single byte. The default is `\n`.
296     ///
297     /// Note that RFC 4180 specifies that record terminators should be `\r\n`.
298     /// To use `\r\n`, use the special `Terminator::CRLF` value.
299     ///
300     /// # Example: CRLF
301     ///
302     /// This shows how to use RFC 4180 compliant record terminators.
303     ///
304     /// ```
305     /// use std::error::Error;
306     /// use csv::{Terminator, WriterBuilder};
307     ///
308     /// # fn main() { example().unwrap(); }
309     /// fn example() -> Result<(), Box<dyn Error>> {
310     ///     let mut wtr = WriterBuilder::new()
311     ///         .terminator(Terminator::CRLF)
312     ///         .from_writer(vec![]);
313     ///     wtr.write_record(&["a", "b", "c"])?;
314     ///     wtr.write_record(&["x", "y", "z"])?;
315     ///
316     ///     let data = String::from_utf8(wtr.into_inner()?)?;
317     ///     assert_eq!(data, "a,b,c\r\nx,y,z\r\n");
318     ///     Ok(())
319     /// }
320     /// ```
terminator(&mut self, term: Terminator) -> &mut WriterBuilder321     pub fn terminator(&mut self, term: Terminator) -> &mut WriterBuilder {
322         self.builder.terminator(term.to_core());
323         self
324     }
325 
326     /// The quoting style to use when writing CSV.
327     ///
328     /// By default, this is set to `QuoteStyle::Necessary`, which will only
329     /// use quotes when they are necessary to preserve the integrity of data.
330     ///
331     /// Note that unless the quote style is set to `Never`, an empty field is
332     /// quoted if it is the only field in a record.
333     ///
334     /// # Example: non-numeric quoting
335     ///
336     /// This shows how to quote non-numeric fields only.
337     ///
338     /// ```
339     /// use std::error::Error;
340     /// use csv::{QuoteStyle, WriterBuilder};
341     ///
342     /// # fn main() { example().unwrap(); }
343     /// fn example() -> Result<(), Box<dyn Error>> {
344     ///     let mut wtr = WriterBuilder::new()
345     ///         .quote_style(QuoteStyle::NonNumeric)
346     ///         .from_writer(vec![]);
347     ///     wtr.write_record(&["a", "5", "c"])?;
348     ///     wtr.write_record(&["3.14", "y", "z"])?;
349     ///
350     ///     let data = String::from_utf8(wtr.into_inner()?)?;
351     ///     assert_eq!(data, "\"a\",5,\"c\"\n3.14,\"y\",\"z\"\n");
352     ///     Ok(())
353     /// }
354     /// ```
355     ///
356     /// # Example: never quote
357     ///
358     /// This shows how the CSV writer can be made to never write quotes, even
359     /// if it sacrifices the integrity of the data.
360     ///
361     /// ```
362     /// use std::error::Error;
363     /// use csv::{QuoteStyle, WriterBuilder};
364     ///
365     /// # fn main() { example().unwrap(); }
366     /// fn example() -> Result<(), Box<dyn Error>> {
367     ///     let mut wtr = WriterBuilder::new()
368     ///         .quote_style(QuoteStyle::Never)
369     ///         .from_writer(vec![]);
370     ///     wtr.write_record(&["a", "foo\nbar", "c"])?;
371     ///     wtr.write_record(&["g\"h\"i", "y", "z"])?;
372     ///
373     ///     let data = String::from_utf8(wtr.into_inner()?)?;
374     ///     assert_eq!(data, "a,foo\nbar,c\ng\"h\"i,y,z\n");
375     ///     Ok(())
376     /// }
377     /// ```
quote_style(&mut self, style: QuoteStyle) -> &mut WriterBuilder378     pub fn quote_style(&mut self, style: QuoteStyle) -> &mut WriterBuilder {
379         self.builder.quote_style(style.to_core());
380         self
381     }
382 
383     /// The quote character to use when writing CSV.
384     ///
385     /// The default is `b'"'`.
386     ///
387     /// # Example
388     ///
389     /// ```
390     /// use std::error::Error;
391     /// use csv::WriterBuilder;
392     ///
393     /// # fn main() { example().unwrap(); }
394     /// fn example() -> Result<(), Box<dyn Error>> {
395     ///     let mut wtr = WriterBuilder::new()
396     ///         .quote(b'\'')
397     ///         .from_writer(vec![]);
398     ///     wtr.write_record(&["a", "foo\nbar", "c"])?;
399     ///     wtr.write_record(&["g'h'i", "y\"y\"y", "z"])?;
400     ///
401     ///     let data = String::from_utf8(wtr.into_inner()?)?;
402     ///     assert_eq!(data, "a,'foo\nbar',c\n'g''h''i',y\"y\"y,z\n");
403     ///     Ok(())
404     /// }
405     /// ```
quote(&mut self, quote: u8) -> &mut WriterBuilder406     pub fn quote(&mut self, quote: u8) -> &mut WriterBuilder {
407         self.builder.quote(quote);
408         self
409     }
410 
411     /// Enable double quote escapes.
412     ///
413     /// This is enabled by default, but it may be disabled. When disabled,
414     /// quotes in field data are escaped instead of doubled.
415     ///
416     /// # Example
417     ///
418     /// ```
419     /// use std::error::Error;
420     /// use csv::WriterBuilder;
421     ///
422     /// # fn main() { example().unwrap(); }
423     /// fn example() -> Result<(), Box<dyn Error>> {
424     ///     let mut wtr = WriterBuilder::new()
425     ///         .double_quote(false)
426     ///         .from_writer(vec![]);
427     ///     wtr.write_record(&["a", "foo\"bar", "c"])?;
428     ///     wtr.write_record(&["x", "y", "z"])?;
429     ///
430     ///     let data = String::from_utf8(wtr.into_inner()?)?;
431     ///     assert_eq!(data, "a,\"foo\\\"bar\",c\nx,y,z\n");
432     ///     Ok(())
433     /// }
434     /// ```
double_quote(&mut self, yes: bool) -> &mut WriterBuilder435     pub fn double_quote(&mut self, yes: bool) -> &mut WriterBuilder {
436         self.builder.double_quote(yes);
437         self
438     }
439 
440     /// The escape character to use when writing CSV.
441     ///
442     /// In some variants of CSV, quotes are escaped using a special escape
443     /// character like `\` (instead of escaping quotes by doubling them).
444     ///
445     /// By default, writing these idiosyncratic escapes is disabled, and is
446     /// only used when `double_quote` is disabled.
447     ///
448     /// # Example
449     ///
450     /// ```
451     /// use std::error::Error;
452     /// use csv::WriterBuilder;
453     ///
454     /// # fn main() { example().unwrap(); }
455     /// fn example() -> Result<(), Box<dyn Error>> {
456     ///     let mut wtr = WriterBuilder::new()
457     ///         .double_quote(false)
458     ///         .escape(b'$')
459     ///         .from_writer(vec![]);
460     ///     wtr.write_record(&["a", "foo\"bar", "c"])?;
461     ///     wtr.write_record(&["x", "y", "z"])?;
462     ///
463     ///     let data = String::from_utf8(wtr.into_inner()?)?;
464     ///     assert_eq!(data, "a,\"foo$\"bar\",c\nx,y,z\n");
465     ///     Ok(())
466     /// }
467     /// ```
escape(&mut self, escape: u8) -> &mut WriterBuilder468     pub fn escape(&mut self, escape: u8) -> &mut WriterBuilder {
469         self.builder.escape(escape);
470         self
471     }
472 
473     /// The comment character that will be used when later reading the file.
474     ///
475     /// If `quote_style` is set to `QuoteStyle::Necessary`, a field will
476     /// be quoted if the comment character is detected anywhere in the field.
477     ///
478     /// The default value is None.
479     ///
480     /// # Example
481     ///
482     /// ```
483     /// use std::error::Error;
484     /// use csv::WriterBuilder;
485     ///
486     /// # fn main() { example().unwrap(); }
487     /// fn example() -> Result<(), Box<dyn Error>> {
488     ///     let mut wtr =
489     ///         WriterBuilder::new().comment(Some(b'#')).from_writer(Vec::new());
490     ///     wtr.write_record(&["# comment", "another"]).unwrap();
491     ///     let buf = wtr.into_inner().unwrap();
492     ///     assert_eq!(String::from_utf8(buf).unwrap(), "\"# comment\",another\n");
493     ///     Ok(())
494     /// }
495     /// ```
comment(&mut self, comment: Option<u8>) -> &mut WriterBuilder496     pub fn comment(&mut self, comment: Option<u8>) -> &mut WriterBuilder {
497         self.builder.comment(comment);
498         self
499     }
500 
501     /// Set the capacity (in bytes) of the internal buffer used in the CSV
502     /// writer. This defaults to a reasonable setting.
buffer_capacity(&mut self, capacity: usize) -> &mut WriterBuilder503     pub fn buffer_capacity(&mut self, capacity: usize) -> &mut WriterBuilder {
504         self.capacity = capacity;
505         self
506     }
507 }
508 
509 /// An already configured CSV writer.
510 ///
511 /// A CSV writer takes as input Rust values and writes those values in a valid
512 /// CSV format as output.
513 ///
514 /// While CSV writing is considerably easier than parsing CSV, a proper writer
515 /// will do a number of things for you:
516 ///
517 /// 1. Quote fields when necessary.
518 /// 2. Check that all records have the same number of fields.
519 /// 3. Write records with a single empty field correctly.
520 /// 4. Automatically serialize normal Rust types to CSV records. When that
521 ///    type is a struct, a header row is automatically written corresponding
522 ///    to the fields of that struct.
523 /// 5. Use buffering intelligently and otherwise avoid allocation. (This means
524 ///    that callers should not do their own buffering.)
525 ///
526 /// All of the above can be configured using a
527 /// [`WriterBuilder`](struct.WriterBuilder.html).
528 /// However, a `Writer` has a couple of convenience constructors (`from_path`
529 /// and `from_writer`) that use the default configuration.
530 ///
531 /// Note that the default configuration of a `Writer` uses `\n` for record
532 /// terminators instead of `\r\n` as specified by RFC 4180. Use the
533 /// `terminator` method on `WriterBuilder` to set the terminator to `\r\n` if
534 /// it's desired.
535 #[derive(Debug)]
536 pub struct Writer<W: io::Write> {
537     core: CoreWriter,
538     wtr: Option<W>,
539     buf: Buffer,
540     state: WriterState,
541 }
542 
543 #[derive(Debug)]
544 struct WriterState {
545     /// Whether the Serde serializer should attempt to write a header row.
546     header: HeaderState,
547     /// Whether inconsistent record lengths are allowed.
548     flexible: bool,
549     /// The number of fields written in the first record. This is compared
550     /// with `fields_written` on all subsequent records to check for
551     /// inconsistent record lengths.
552     first_field_count: Option<u64>,
553     /// The number of fields written in this record. This is used to report
554     /// errors for inconsistent record lengths if `flexible` is disabled.
555     fields_written: u64,
556     /// This is set immediately before flushing the buffer and then unset
557     /// immediately after flushing the buffer. This avoids flushing the buffer
558     /// twice if the inner writer panics.
559     panicked: bool,
560 }
561 
562 /// HeaderState encodes a small state machine for handling header writes.
563 #[derive(Debug)]
564 enum HeaderState {
565     /// Indicates that we should attempt to write a header.
566     Write,
567     /// Indicates that writing a header was attempted, and a header was written.
568     DidWrite,
569     /// Indicates that writing a header was attempted, but no headers were
570     /// written or the attempt failed.
571     DidNotWrite,
572     /// This state is used when headers are disabled. It cannot transition
573     /// to any other state.
574     None,
575 }
576 
577 /// A simple internal buffer for buffering writes.
578 ///
579 /// We need this because the `csv_core` APIs want to write into a `&mut [u8]`,
580 /// which is not available with the `std::io::BufWriter` API.
581 #[derive(Debug)]
582 struct Buffer {
583     /// The contents of the buffer.
584     buf: Vec<u8>,
585     /// The number of bytes written to the buffer.
586     len: usize,
587 }
588 
589 impl<W: io::Write> Drop for Writer<W> {
drop(&mut self)590     fn drop(&mut self) {
591         if self.wtr.is_some() && !self.state.panicked {
592             let _ = self.flush();
593         }
594     }
595 }
596 
597 impl Writer<File> {
598     /// Build a CSV writer with a default configuration that writes data to the
599     /// given file path. The file is truncated if it already exists.
600     ///
601     /// If there was a problem opening the file at the given path, then this
602     /// returns the corresponding error.
603     ///
604     /// # Example
605     ///
606     /// ```no_run
607     /// use std::error::Error;
608     /// use csv::Writer;
609     ///
610     /// # fn main() { example().unwrap(); }
611     /// fn example() -> Result<(), Box<dyn Error>> {
612     ///     let mut wtr = Writer::from_path("foo.csv")?;
613     ///     wtr.write_record(&["a", "b", "c"])?;
614     ///     wtr.write_record(&["x", "y", "z"])?;
615     ///     wtr.flush()?;
616     ///     Ok(())
617     /// }
618     /// ```
from_path<P: AsRef<Path>>(path: P) -> Result<Writer<File>>619     pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Writer<File>> {
620         WriterBuilder::new().from_path(path)
621     }
622 }
623 
624 impl<W: io::Write> Writer<W> {
new(builder: &WriterBuilder, wtr: W) -> Writer<W>625     fn new(builder: &WriterBuilder, wtr: W) -> Writer<W> {
626         let header_state = if builder.has_headers {
627             HeaderState::Write
628         } else {
629             HeaderState::None
630         };
631         Writer {
632             core: builder.builder.build(),
633             wtr: Some(wtr),
634             buf: Buffer { buf: vec![0; builder.capacity], len: 0 },
635             state: WriterState {
636                 header: header_state,
637                 flexible: builder.flexible,
638                 first_field_count: None,
639                 fields_written: 0,
640                 panicked: false,
641             },
642         }
643     }
644 
645     /// Build a CSV writer with a default configuration that writes data to
646     /// `wtr`.
647     ///
648     /// Note that the CSV writer is buffered automatically, so you should not
649     /// wrap `wtr` in a buffered writer like `io::BufWriter`.
650     ///
651     /// # Example
652     ///
653     /// ```
654     /// use std::error::Error;
655     /// use csv::Writer;
656     ///
657     /// # fn main() { example().unwrap(); }
658     /// fn example() -> Result<(), Box<dyn Error>> {
659     ///     let mut wtr = Writer::from_writer(vec![]);
660     ///     wtr.write_record(&["a", "b", "c"])?;
661     ///     wtr.write_record(&["x", "y", "z"])?;
662     ///
663     ///     let data = String::from_utf8(wtr.into_inner()?)?;
664     ///     assert_eq!(data, "a,b,c\nx,y,z\n");
665     ///     Ok(())
666     /// }
667     /// ```
from_writer(wtr: W) -> Writer<W>668     pub fn from_writer(wtr: W) -> Writer<W> {
669         WriterBuilder::new().from_writer(wtr)
670     }
671 
672     /// Serialize a single record using Serde.
673     ///
674     /// # Example
675     ///
676     /// This shows how to serialize normal Rust structs as CSV records. The
677     /// fields of the struct are used to write a header row automatically.
678     /// (Writing the header row automatically can be disabled by building the
679     /// CSV writer with a [`WriterBuilder`](struct.WriterBuilder.html) and
680     /// calling the `has_headers` method.)
681     ///
682     /// ```
683     /// use std::error::Error;
684     ///
685     /// use csv::Writer;
686     ///
687     /// #[derive(serde::Serialize)]
688     /// struct Row<'a> {
689     ///     city: &'a str,
690     ///     country: &'a str,
691     ///     // Serde allows us to name our headers exactly,
692     ///     // even if they don't match our struct field names.
693     ///     #[serde(rename = "popcount")]
694     ///     population: u64,
695     /// }
696     ///
697     /// # fn main() { example().unwrap(); }
698     /// fn example() -> Result<(), Box<dyn Error>> {
699     ///     let mut wtr = Writer::from_writer(vec![]);
700     ///     wtr.serialize(Row {
701     ///         city: "Boston",
702     ///         country: "United States",
703     ///         population: 4628910,
704     ///     })?;
705     ///     wtr.serialize(Row {
706     ///         city: "Concord",
707     ///         country: "United States",
708     ///         population: 42695,
709     ///     })?;
710     ///
711     ///     let data = String::from_utf8(wtr.into_inner()?)?;
712     ///     assert_eq!(data, "\
713     /// city,country,popcount
714     /// Boston,United States,4628910
715     /// Concord,United States,42695
716     /// ");
717     ///     Ok(())
718     /// }
719     /// ```
720     ///
721     /// # Rules
722     ///
723     /// The behavior of `serialize` is fairly simple:
724     ///
725     /// 1. Nested containers (tuples, `Vec`s, structs, etc.) are always
726     ///    flattened (depth-first order).
727     ///
728     /// 2. If `has_headers` is `true` and the type contains field names, then
729     ///    a header row is automatically generated.
730     ///
731     /// However, some container types cannot be serialized, and if
732     /// `has_headers` is `true`, there are some additional restrictions on the
733     /// types that can be serialized. See below for details.
734     ///
735     /// For the purpose of this section, Rust types can be divided into three
736     /// categories: scalars, non-struct containers, and structs.
737     ///
738     /// ## Scalars
739     ///
740     /// Single values with no field names are written like the following. Note
741     /// that some of the outputs may be quoted, according to the selected
742     /// quoting style.
743     ///
744     /// | Name | Example Type | Example Value | Output |
745     /// | ---- | ---- | ---- | ---- |
746     /// | boolean | `bool` | `true` | `true` |
747     /// | integers | `i8`, `i16`, `i32`, `i64`, `i128`, `u8`, `u16`, `u32`, `u64`, `u128` | `5` | `5` |
748     /// | floats | `f32`, `f64` | `3.14` | `3.14` |
749     /// | character | `char` | `'☃'` | `☃` |
750     /// | string | `&str` | `"hi"` | `hi` |
751     /// | bytes | `&[u8]` | `b"hi"[..]` | `hi` |
752     /// | option | `Option` | `None` | *empty* |
753     /// | option |          | `Some(5)` | `5` |
754     /// | unit | `()` | `()` | *empty* |
755     /// | unit struct | `struct Foo;` | `Foo` | `Foo` |
756     /// | unit enum variant | `enum E { A, B }` | `E::A` | `A` |
757     /// | newtype struct | `struct Foo(u8);` | `Foo(5)` | `5` |
758     /// | newtype enum variant | `enum E { A(u8) }` | `E::A(5)` | `5` |
759     ///
760     /// Note that this table includes simple structs and enums. For example, to
761     /// serialize a field from either an integer or a float type, one can do
762     /// this:
763     ///
764     /// ```
765     /// use std::error::Error;
766     ///
767     /// use csv::Writer;
768     ///
769     /// #[derive(serde::Serialize)]
770     /// struct Row {
771     ///     label: String,
772     ///     value: Value,
773     /// }
774     ///
775     /// #[derive(serde::Serialize)]
776     /// enum Value {
777     ///     Integer(i64),
778     ///     Float(f64),
779     /// }
780     ///
781     /// # fn main() { example().unwrap(); }
782     /// fn example() -> Result<(), Box<dyn Error>> {
783     ///     let mut wtr = Writer::from_writer(vec![]);
784     ///     wtr.serialize(Row {
785     ///         label: "foo".to_string(),
786     ///         value: Value::Integer(3),
787     ///     })?;
788     ///     wtr.serialize(Row {
789     ///         label: "bar".to_string(),
790     ///         value: Value::Float(3.14),
791     ///     })?;
792     ///
793     ///     let data = String::from_utf8(wtr.into_inner()?)?;
794     ///     assert_eq!(data, "\
795     /// label,value
796     /// foo,3
797     /// bar,3.14
798     /// ");
799     ///     Ok(())
800     /// }
801     /// ```
802     ///
803     /// ## Non-Struct Containers
804     ///
805     /// Nested containers are flattened to their scalar components, with the
806     /// exception of a few types that are not allowed:
807     ///
808     /// | Name | Example Type | Example Value | Output |
809     /// | ---- | ---- | ---- | ---- |
810     /// | sequence | `Vec<u8>` | `vec![1, 2, 3]` | `1,2,3` |
811     /// | tuple | `(u8, bool)` | `(5, true)` | `5,true` |
812     /// | tuple struct | `Foo(u8, bool)` | `Foo(5, true)` | `5,true` |
813     /// | tuple enum variant | `enum E { A(u8, bool) }` | `E::A(5, true)` | *error* |
814     /// | struct enum variant | `enum E { V { a: u8, b: bool } }` | `E::V { a: 5, b: true }` | *error* |
815     /// | map | `BTreeMap<K, V>` | `BTreeMap::new()` | *error* |
816     ///
817     /// ## Structs
818     ///
819     /// Like the other containers, structs are flattened to their scalar
820     /// components:
821     ///
822     /// | Name | Example Type | Example Value | Output |
823     /// | ---- | ---- | ---- | ---- |
824     /// | struct | `struct Foo { a: u8, b: bool }` | `Foo { a: 5, b: true }` | `5,true` |
825     ///
826     /// If `has_headers` is `false`, then there are no additional restrictions;
827     /// types can be nested arbitrarily. For example:
828     ///
829     /// ```
830     /// use std::error::Error;
831     ///
832     /// use csv::WriterBuilder;
833     ///
834     /// #[derive(serde::Serialize)]
835     /// struct Row {
836     ///     label: String,
837     ///     values: Vec<f64>,
838     /// }
839     ///
840     /// # fn main() { example().unwrap(); }
841     /// fn example() -> Result<(), Box<dyn Error>> {
842     ///     let mut wtr = WriterBuilder::new()
843     ///         .has_headers(false)
844     ///         .from_writer(vec![]);
845     ///     wtr.serialize(Row {
846     ///         label: "foo".to_string(),
847     ///         values: vec![1.1234, 2.5678, 3.14],
848     ///     })?;
849     ///
850     ///     let data = String::from_utf8(wtr.into_inner()?)?;
851     ///     assert_eq!(data, "\
852     /// foo,1.1234,2.5678,3.14
853     /// ");
854     ///     Ok(())
855     /// }
856     /// ```
857     ///
858     /// However, if `has_headers` were enabled in the above example, then
859     /// serialization would return an error. Specifically, when `has_headers` is
860     /// `true`, there are two restrictions:
861     ///
862     /// 1. Named field values in structs must be scalars.
863     ///
864     /// 2. All scalars must be named field values in structs.
865     ///
866     /// Other than these two restrictions, types can be nested arbitrarily.
867     /// Here are a few examples:
868     ///
869     /// | Value | Header | Record |
870     /// | ---- | ---- | ---- |
871     /// | `(Foo { x: 5, y: 6 }, Bar { z: true })` | `x,y,z` | `5,6,true` |
872     /// | `vec![Foo { x: 5, y: 6 }, Foo { x: 7, y: 8 }]` | `x,y,x,y` | `5,6,7,8` |
873     /// | `(Foo { x: 5, y: 6 }, vec![Bar { z: Baz(true) }])` | `x,y,z` | `5,6,true` |
874     /// | `Foo { x: 5, y: (6, 7) }` | *error: restriction 1* | `5,6,7` |
875     /// | `(5, Foo { x: 6, y: 7 }` | *error: restriction 2* | `5,6,7` |
876     /// | `(Foo { x: 5, y: 6 }, true)` | *error: restriction 2* | `5,6,true` |
serialize<S: Serialize>(&mut self, record: S) -> Result<()>877     pub fn serialize<S: Serialize>(&mut self, record: S) -> Result<()> {
878         if let HeaderState::Write = self.state.header {
879             let wrote_header = serialize_header(self, &record)?;
880             if wrote_header {
881                 self.write_terminator()?;
882                 self.state.header = HeaderState::DidWrite;
883             } else {
884                 self.state.header = HeaderState::DidNotWrite;
885             };
886         }
887         serialize(self, &record)?;
888         self.write_terminator()?;
889         Ok(())
890     }
891 
892     /// Write a single record.
893     ///
894     /// This method accepts something that can be turned into an iterator that
895     /// yields elements that can be represented by a `&[u8]`.
896     ///
897     /// This may be called with an empty iterator, which will cause a record
898     /// terminator to be written. If no fields had been written, then a single
899     /// empty field is written before the terminator.
900     ///
901     /// # Example
902     ///
903     /// ```
904     /// use std::error::Error;
905     /// use csv::Writer;
906     ///
907     /// # fn main() { example().unwrap(); }
908     /// fn example() -> Result<(), Box<dyn Error>> {
909     ///     let mut wtr = Writer::from_writer(vec![]);
910     ///     wtr.write_record(&["a", "b", "c"])?;
911     ///     wtr.write_record(&["x", "y", "z"])?;
912     ///
913     ///     let data = String::from_utf8(wtr.into_inner()?)?;
914     ///     assert_eq!(data, "a,b,c\nx,y,z\n");
915     ///     Ok(())
916     /// }
917     /// ```
write_record<I, T>(&mut self, record: I) -> Result<()> where I: IntoIterator<Item = T>, T: AsRef<[u8]>,918     pub fn write_record<I, T>(&mut self, record: I) -> Result<()>
919     where
920         I: IntoIterator<Item = T>,
921         T: AsRef<[u8]>,
922     {
923         for field in record.into_iter() {
924             self.write_field_impl(field)?;
925         }
926         self.write_terminator()
927     }
928 
929     /// Write a single `ByteRecord`.
930     ///
931     /// This method accepts a borrowed `ByteRecord` and writes its contents
932     /// to the underlying writer.
933     ///
934     /// This is similar to `write_record` except that it specifically requires
935     /// a `ByteRecord`. This permits the writer to possibly write the record
936     /// more quickly than the more generic `write_record`.
937     ///
938     /// This may be called with an empty record, which will cause a record
939     /// terminator to be written. If no fields had been written, then a single
940     /// empty field is written before the terminator.
941     ///
942     /// # Example
943     ///
944     /// ```
945     /// use std::error::Error;
946     /// use csv::{ByteRecord, Writer};
947     ///
948     /// # fn main() { example().unwrap(); }
949     /// fn example() -> Result<(), Box<dyn Error>> {
950     ///     let mut wtr = Writer::from_writer(vec![]);
951     ///     wtr.write_byte_record(&ByteRecord::from(&["a", "b", "c"][..]))?;
952     ///     wtr.write_byte_record(&ByteRecord::from(&["x", "y", "z"][..]))?;
953     ///
954     ///     let data = String::from_utf8(wtr.into_inner()?)?;
955     ///     assert_eq!(data, "a,b,c\nx,y,z\n");
956     ///     Ok(())
957     /// }
958     /// ```
959     #[inline(never)]
write_byte_record(&mut self, record: &ByteRecord) -> Result<()>960     pub fn write_byte_record(&mut self, record: &ByteRecord) -> Result<()> {
961         if record.as_slice().is_empty() {
962             return self.write_record(record);
963         }
964         // The idea here is to find a fast path for shuffling our record into
965         // our buffer as quickly as possible. We do this because the underlying
966         // "core" CSV writer does a lot of book-keeping to maintain its state
967         // oriented API.
968         //
969         // The fast path occurs when we know our record will fit in whatever
970         // space we have left in our buffer. We can actually quickly compute
971         // the upper bound on the space required:
972         let upper_bound =
973             // The data itself plus the worst case: every byte is a quote.
974             (2 * record.as_slice().len())
975             // The number of field delimiters.
976             + (record.len().saturating_sub(1))
977             // The maximum number of quotes inserted around each field.
978             + (2 * record.len())
979             // The maximum number of bytes for the terminator.
980             + 2;
981         if self.buf.writable().len() < upper_bound {
982             return self.write_record(record);
983         }
984         let mut first = true;
985         for field in record.iter() {
986             if !first {
987                 self.buf.writable()[0] = self.core.get_delimiter();
988                 self.buf.written(1);
989             }
990             first = false;
991 
992             if !self.core.should_quote(field) {
993                 self.buf.writable()[..field.len()].copy_from_slice(field);
994                 self.buf.written(field.len());
995             } else {
996                 self.buf.writable()[0] = self.core.get_quote();
997                 self.buf.written(1);
998                 let (res, nin, nout) = csv_core::quote(
999                     field,
1000                     self.buf.writable(),
1001                     self.core.get_quote(),
1002                     self.core.get_escape(),
1003                     self.core.get_double_quote(),
1004                 );
1005                 debug_assert!(res == WriteResult::InputEmpty);
1006                 debug_assert!(nin == field.len());
1007                 self.buf.written(nout);
1008                 self.buf.writable()[0] = self.core.get_quote();
1009                 self.buf.written(1);
1010             }
1011         }
1012         self.state.fields_written = record.len() as u64;
1013         self.write_terminator_into_buffer()
1014     }
1015 
1016     /// Write a single field.
1017     ///
1018     /// One should prefer using `write_record` over this method. It is provided
1019     /// for cases where writing a field at a time is more convenient than
1020     /// writing a record at a time.
1021     ///
1022     /// Note that if this API is used, `write_record` should be called with an
1023     /// empty iterator to write a record terminator.
1024     ///
1025     /// # Example
1026     ///
1027     /// ```
1028     /// use std::error::Error;
1029     /// use csv::Writer;
1030     ///
1031     /// # fn main() { example().unwrap(); }
1032     /// fn example() -> Result<(), Box<dyn Error>> {
1033     ///     let mut wtr = Writer::from_writer(vec![]);
1034     ///     wtr.write_field("a")?;
1035     ///     wtr.write_field("b")?;
1036     ///     wtr.write_field("c")?;
1037     ///     wtr.write_record(None::<&[u8]>)?;
1038     ///     wtr.write_field("x")?;
1039     ///     wtr.write_field("y")?;
1040     ///     wtr.write_field("z")?;
1041     ///     wtr.write_record(None::<&[u8]>)?;
1042     ///
1043     ///     let data = String::from_utf8(wtr.into_inner()?)?;
1044     ///     assert_eq!(data, "a,b,c\nx,y,z\n");
1045     ///     Ok(())
1046     /// }
1047     /// ```
write_field<T: AsRef<[u8]>>(&mut self, field: T) -> Result<()>1048     pub fn write_field<T: AsRef<[u8]>>(&mut self, field: T) -> Result<()> {
1049         self.write_field_impl(field)
1050     }
1051 
1052     /// Implementation of write_field.
1053     ///
1054     /// This is a separate method so we can force the compiler to inline it
1055     /// into write_record.
1056     #[inline(always)]
write_field_impl<T: AsRef<[u8]>>(&mut self, field: T) -> Result<()>1057     fn write_field_impl<T: AsRef<[u8]>>(&mut self, field: T) -> Result<()> {
1058         if self.state.fields_written > 0 {
1059             self.write_delimiter()?;
1060         }
1061         let mut field = field.as_ref();
1062         loop {
1063             let (res, nin, nout) = self.core.field(field, self.buf.writable());
1064             field = &field[nin..];
1065             self.buf.written(nout);
1066             match res {
1067                 WriteResult::InputEmpty => {
1068                     self.state.fields_written += 1;
1069                     return Ok(());
1070                 }
1071                 WriteResult::OutputFull => self.flush_buf()?,
1072             }
1073         }
1074     }
1075 
1076     /// Flush the contents of the internal buffer to the underlying writer.
1077     ///
1078     /// If there was a problem writing to the underlying writer, then an error
1079     /// is returned.
1080     ///
1081     /// Note that this also flushes the underlying writer.
flush(&mut self) -> io::Result<()>1082     pub fn flush(&mut self) -> io::Result<()> {
1083         self.flush_buf()?;
1084         self.wtr.as_mut().unwrap().flush()?;
1085         Ok(())
1086     }
1087 
1088     /// Flush the contents of the internal buffer to the underlying writer,
1089     /// without flushing the underlying writer.
flush_buf(&mut self) -> io::Result<()>1090     fn flush_buf(&mut self) -> io::Result<()> {
1091         self.state.panicked = true;
1092         let result = self.wtr.as_mut().unwrap().write_all(self.buf.readable());
1093         self.state.panicked = false;
1094         result?;
1095         self.buf.clear();
1096         Ok(())
1097     }
1098 
1099     /// Return a reference to the underlying writer.
get_ref(&self) -> &W1100     pub fn get_ref(&self) -> &W {
1101         self.wtr.as_ref().unwrap()
1102     }
1103 
1104     /// Flush the contents of the internal buffer and return the underlying
1105     /// writer.
into_inner( mut self, ) -> result::Result<W, IntoInnerError<Writer<W>>>1106     pub fn into_inner(
1107         mut self,
1108     ) -> result::Result<W, IntoInnerError<Writer<W>>> {
1109         match self.flush() {
1110             Ok(()) => Ok(self.wtr.take().unwrap()),
1111             Err(err) => Err(IntoInnerError::new(self, err)),
1112         }
1113     }
1114 
1115     /// Write a CSV delimiter.
write_delimiter(&mut self) -> Result<()>1116     fn write_delimiter(&mut self) -> Result<()> {
1117         loop {
1118             let (res, nout) = self.core.delimiter(self.buf.writable());
1119             self.buf.written(nout);
1120             match res {
1121                 WriteResult::InputEmpty => return Ok(()),
1122                 WriteResult::OutputFull => self.flush_buf()?,
1123             }
1124         }
1125     }
1126 
1127     /// Write a CSV terminator.
write_terminator(&mut self) -> Result<()>1128     fn write_terminator(&mut self) -> Result<()> {
1129         self.check_field_count()?;
1130         loop {
1131             let (res, nout) = self.core.terminator(self.buf.writable());
1132             self.buf.written(nout);
1133             match res {
1134                 WriteResult::InputEmpty => {
1135                     self.state.fields_written = 0;
1136                     return Ok(());
1137                 }
1138                 WriteResult::OutputFull => self.flush_buf()?,
1139             }
1140         }
1141     }
1142 
1143     /// Write a CSV terminator that is guaranteed to fit into the current
1144     /// buffer.
1145     #[inline(never)]
write_terminator_into_buffer(&mut self) -> Result<()>1146     fn write_terminator_into_buffer(&mut self) -> Result<()> {
1147         self.check_field_count()?;
1148         match self.core.get_terminator() {
1149             csv_core::Terminator::CRLF => {
1150                 self.buf.writable()[0] = b'\r';
1151                 self.buf.writable()[1] = b'\n';
1152                 self.buf.written(2);
1153             }
1154             csv_core::Terminator::Any(b) => {
1155                 self.buf.writable()[0] = b;
1156                 self.buf.written(1);
1157             }
1158             _ => unreachable!(),
1159         }
1160         self.state.fields_written = 0;
1161         Ok(())
1162     }
1163 
check_field_count(&mut self) -> Result<()>1164     fn check_field_count(&mut self) -> Result<()> {
1165         if !self.state.flexible {
1166             match self.state.first_field_count {
1167                 None => {
1168                     self.state.first_field_count =
1169                         Some(self.state.fields_written);
1170                 }
1171                 Some(expected) if expected != self.state.fields_written => {
1172                     return Err(Error::new(ErrorKind::UnequalLengths {
1173                         pos: None,
1174                         expected_len: expected,
1175                         len: self.state.fields_written,
1176                     }))
1177                 }
1178                 Some(_) => {}
1179             }
1180         }
1181         Ok(())
1182     }
1183 }
1184 
1185 impl Buffer {
1186     /// Returns a slice of the buffer's current contents.
1187     ///
1188     /// The slice returned may be empty.
1189     #[inline]
readable(&self) -> &[u8]1190     fn readable(&self) -> &[u8] {
1191         &self.buf[..self.len]
1192     }
1193 
1194     /// Returns a mutable slice of the remaining space in this buffer.
1195     ///
1196     /// The slice returned may be empty.
1197     #[inline]
writable(&mut self) -> &mut [u8]1198     fn writable(&mut self) -> &mut [u8] {
1199         &mut self.buf[self.len..]
1200     }
1201 
1202     /// Indicates that `n` bytes have been written to this buffer.
1203     #[inline]
written(&mut self, n: usize)1204     fn written(&mut self, n: usize) {
1205         self.len += n;
1206     }
1207 
1208     /// Clear the buffer.
1209     #[inline]
clear(&mut self)1210     fn clear(&mut self) {
1211         self.len = 0;
1212     }
1213 }
1214 
1215 #[cfg(test)]
1216 mod tests {
1217     use std::io::{self, Write};
1218 
1219     use serde::{serde_if_integer128, Serialize};
1220 
1221     use crate::{
1222         byte_record::ByteRecord, error::ErrorKind, string_record::StringRecord,
1223     };
1224 
1225     use super::{Writer, WriterBuilder};
1226 
wtr_as_string(wtr: Writer<Vec<u8>>) -> String1227     fn wtr_as_string(wtr: Writer<Vec<u8>>) -> String {
1228         String::from_utf8(wtr.into_inner().unwrap()).unwrap()
1229     }
1230 
1231     #[test]
one_record()1232     fn one_record() {
1233         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1234         wtr.write_record(&["a", "b", "c"]).unwrap();
1235 
1236         assert_eq!(wtr_as_string(wtr), "a,b,c\n");
1237     }
1238 
1239     #[test]
one_string_record()1240     fn one_string_record() {
1241         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1242         wtr.write_record(&StringRecord::from(vec!["a", "b", "c"])).unwrap();
1243 
1244         assert_eq!(wtr_as_string(wtr), "a,b,c\n");
1245     }
1246 
1247     #[test]
one_byte_record()1248     fn one_byte_record() {
1249         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1250         wtr.write_record(&ByteRecord::from(vec!["a", "b", "c"])).unwrap();
1251 
1252         assert_eq!(wtr_as_string(wtr), "a,b,c\n");
1253     }
1254 
1255     #[test]
raw_one_byte_record()1256     fn raw_one_byte_record() {
1257         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1258         wtr.write_byte_record(&ByteRecord::from(vec!["a", "b", "c"])).unwrap();
1259 
1260         assert_eq!(wtr_as_string(wtr), "a,b,c\n");
1261     }
1262 
1263     #[test]
one_empty_record()1264     fn one_empty_record() {
1265         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1266         wtr.write_record(&[""]).unwrap();
1267 
1268         assert_eq!(wtr_as_string(wtr), "\"\"\n");
1269     }
1270 
1271     #[test]
raw_one_empty_record()1272     fn raw_one_empty_record() {
1273         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1274         wtr.write_byte_record(&ByteRecord::from(vec![""])).unwrap();
1275 
1276         assert_eq!(wtr_as_string(wtr), "\"\"\n");
1277     }
1278 
1279     #[test]
two_empty_records()1280     fn two_empty_records() {
1281         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1282         wtr.write_record(&[""]).unwrap();
1283         wtr.write_record(&[""]).unwrap();
1284 
1285         assert_eq!(wtr_as_string(wtr), "\"\"\n\"\"\n");
1286     }
1287 
1288     #[test]
raw_two_empty_records()1289     fn raw_two_empty_records() {
1290         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1291         wtr.write_byte_record(&ByteRecord::from(vec![""])).unwrap();
1292         wtr.write_byte_record(&ByteRecord::from(vec![""])).unwrap();
1293 
1294         assert_eq!(wtr_as_string(wtr), "\"\"\n\"\"\n");
1295     }
1296 
1297     #[test]
unequal_records_bad()1298     fn unequal_records_bad() {
1299         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1300         wtr.write_record(&ByteRecord::from(vec!["a", "b", "c"])).unwrap();
1301         let err = wtr.write_record(&ByteRecord::from(vec!["a"])).unwrap_err();
1302         match *err.kind() {
1303             ErrorKind::UnequalLengths { ref pos, expected_len, len } => {
1304                 assert!(pos.is_none());
1305                 assert_eq!(expected_len, 3);
1306                 assert_eq!(len, 1);
1307             }
1308             ref x => {
1309                 panic!("expected UnequalLengths error, but got '{:?}'", x);
1310             }
1311         }
1312     }
1313 
1314     #[test]
raw_unequal_records_bad()1315     fn raw_unequal_records_bad() {
1316         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1317         wtr.write_byte_record(&ByteRecord::from(vec!["a", "b", "c"])).unwrap();
1318         let err =
1319             wtr.write_byte_record(&ByteRecord::from(vec!["a"])).unwrap_err();
1320         match *err.kind() {
1321             ErrorKind::UnequalLengths { ref pos, expected_len, len } => {
1322                 assert!(pos.is_none());
1323                 assert_eq!(expected_len, 3);
1324                 assert_eq!(len, 1);
1325             }
1326             ref x => {
1327                 panic!("expected UnequalLengths error, but got '{:?}'", x);
1328             }
1329         }
1330     }
1331 
1332     #[test]
unequal_records_ok()1333     fn unequal_records_ok() {
1334         let mut wtr = WriterBuilder::new().flexible(true).from_writer(vec![]);
1335         wtr.write_record(&ByteRecord::from(vec!["a", "b", "c"])).unwrap();
1336         wtr.write_record(&ByteRecord::from(vec!["a"])).unwrap();
1337         assert_eq!(wtr_as_string(wtr), "a,b,c\na\n");
1338     }
1339 
1340     #[test]
raw_unequal_records_ok()1341     fn raw_unequal_records_ok() {
1342         let mut wtr = WriterBuilder::new().flexible(true).from_writer(vec![]);
1343         wtr.write_byte_record(&ByteRecord::from(vec!["a", "b", "c"])).unwrap();
1344         wtr.write_byte_record(&ByteRecord::from(vec!["a"])).unwrap();
1345         assert_eq!(wtr_as_string(wtr), "a,b,c\na\n");
1346     }
1347 
1348     #[test]
full_buffer_should_not_flush_underlying()1349     fn full_buffer_should_not_flush_underlying() {
1350         struct MarkWriteAndFlush(Vec<u8>);
1351 
1352         impl MarkWriteAndFlush {
1353             fn to_str(self) -> String {
1354                 String::from_utf8(self.0).unwrap()
1355             }
1356         }
1357 
1358         impl Write for MarkWriteAndFlush {
1359             fn write(&mut self, data: &[u8]) -> io::Result<usize> {
1360                 self.0.write(b">")?;
1361                 let written = self.0.write(data)?;
1362                 self.0.write(b"<")?;
1363 
1364                 Ok(written)
1365             }
1366 
1367             fn flush(&mut self) -> io::Result<()> {
1368                 self.0.write(b"!")?;
1369                 Ok(())
1370             }
1371         }
1372 
1373         let underlying = MarkWriteAndFlush(vec![]);
1374         let mut wtr =
1375             WriterBuilder::new().buffer_capacity(4).from_writer(underlying);
1376 
1377         wtr.write_byte_record(&ByteRecord::from(vec!["a", "b"])).unwrap();
1378         wtr.write_byte_record(&ByteRecord::from(vec!["c", "d"])).unwrap();
1379         wtr.flush().unwrap();
1380         wtr.write_byte_record(&ByteRecord::from(vec!["e", "f"])).unwrap();
1381 
1382         let got = wtr.into_inner().unwrap().to_str();
1383 
1384         // As the buffer size is 4 we should write each record separately, and
1385         // flush when explicitly called and implictly in into_inner.
1386         assert_eq!(got, ">a,b\n<>c,d\n<!>e,f\n<!");
1387     }
1388 
1389     #[test]
serialize_with_headers()1390     fn serialize_with_headers() {
1391         #[derive(Serialize)]
1392         struct Row {
1393             foo: i32,
1394             bar: f64,
1395             baz: bool,
1396         }
1397 
1398         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1399         wtr.serialize(Row { foo: 42, bar: 42.5, baz: true }).unwrap();
1400         assert_eq!(wtr_as_string(wtr), "foo,bar,baz\n42,42.5,true\n");
1401     }
1402 
1403     #[test]
serialize_no_headers()1404     fn serialize_no_headers() {
1405         #[derive(Serialize)]
1406         struct Row {
1407             foo: i32,
1408             bar: f64,
1409             baz: bool,
1410         }
1411 
1412         let mut wtr =
1413             WriterBuilder::new().has_headers(false).from_writer(vec![]);
1414         wtr.serialize(Row { foo: 42, bar: 42.5, baz: true }).unwrap();
1415         assert_eq!(wtr_as_string(wtr), "42,42.5,true\n");
1416     }
1417 
1418     serde_if_integer128! {
1419         #[test]
1420         fn serialize_no_headers_128() {
1421             #[derive(Serialize)]
1422             struct Row {
1423                 foo: i128,
1424                 bar: f64,
1425                 baz: bool,
1426             }
1427 
1428             let mut wtr =
1429                 WriterBuilder::new().has_headers(false).from_writer(vec![]);
1430             wtr.serialize(Row {
1431                 foo: 9_223_372_036_854_775_808,
1432                 bar: 42.5,
1433                 baz: true,
1434             }).unwrap();
1435             assert_eq!(wtr_as_string(wtr), "9223372036854775808,42.5,true\n");
1436         }
1437     }
1438 
1439     #[test]
serialize_tuple()1440     fn serialize_tuple() {
1441         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1442         wtr.serialize((true, 1.3, "hi")).unwrap();
1443         assert_eq!(wtr_as_string(wtr), "true,1.3,hi\n");
1444     }
1445 
1446     #[test]
comment_char_is_automatically_quoted()1447     fn comment_char_is_automatically_quoted() {
1448         let mut wtr =
1449             WriterBuilder::new().comment(Some(b'#')).from_writer(Vec::new());
1450         wtr.write_record(&["# comment", "another"]).unwrap();
1451         let buf = wtr.into_inner().unwrap();
1452         assert_eq!(String::from_utf8(buf).unwrap(), "\"# comment\",another\n");
1453     }
1454 }
1455