1 use std::fs::File;
2 use std::io;
3 use std::path::Path;
4 use std::result;
5 
6 use csv_core::{
7     self, WriteResult, Writer as CoreWriter,
8     WriterBuilder as CoreWriterBuilder,
9 };
10 use serde::Serialize;
11 
12 use crate::byte_record::ByteRecord;
13 use crate::error::{Error, ErrorKind, IntoInnerError, Result};
14 use crate::serializer::{serialize, serialize_header};
15 use crate::{QuoteStyle, Terminator};
16 
17 /// Builds a CSV writer with various configuration knobs.
18 ///
19 /// This builder can be used to tweak the field delimiter, record terminator
20 /// and more. Once a CSV `Writer` is built, its configuration cannot be
21 /// changed.
22 #[derive(Debug)]
23 pub struct WriterBuilder {
24     builder: CoreWriterBuilder,
25     capacity: usize,
26     flexible: bool,
27     has_headers: bool,
28 }
29 
30 impl Default for WriterBuilder {
default() -> WriterBuilder31     fn default() -> WriterBuilder {
32         WriterBuilder {
33             builder: CoreWriterBuilder::default(),
34             capacity: 8 * (1 << 10),
35             flexible: false,
36             has_headers: true,
37         }
38     }
39 }
40 
41 impl WriterBuilder {
42     /// Create a new builder for configuring CSV writing.
43     ///
44     /// To convert a builder into a writer, call one of the methods starting
45     /// with `from_`.
46     ///
47     /// # Example
48     ///
49     /// ```
50     /// use std::error::Error;
51     /// use csv::WriterBuilder;
52     ///
53     /// # fn main() { example().unwrap(); }
54     /// fn example() -> Result<(), Box<dyn Error>> {
55     ///     let mut wtr = WriterBuilder::new().from_writer(vec![]);
56     ///     wtr.write_record(&["a", "b", "c"])?;
57     ///     wtr.write_record(&["x", "y", "z"])?;
58     ///
59     ///     let data = String::from_utf8(wtr.into_inner()?)?;
60     ///     assert_eq!(data, "a,b,c\nx,y,z\n");
61     ///     Ok(())
62     /// }
63     /// ```
new() -> WriterBuilder64     pub fn new() -> WriterBuilder {
65         WriterBuilder::default()
66     }
67 
68     /// Build a CSV writer from this configuration that writes data to the
69     /// given file path. The file is truncated if it already exists.
70     ///
71     /// If there was a problem opening the file at the given path, then this
72     /// returns the corresponding error.
73     ///
74     /// # Example
75     ///
76     /// ```no_run
77     /// use std::error::Error;
78     /// use csv::WriterBuilder;
79     ///
80     /// # fn main() { example().unwrap(); }
81     /// fn example() -> Result<(), Box<dyn Error>> {
82     ///     let mut wtr = WriterBuilder::new().from_path("foo.csv")?;
83     ///     wtr.write_record(&["a", "b", "c"])?;
84     ///     wtr.write_record(&["x", "y", "z"])?;
85     ///     wtr.flush()?;
86     ///     Ok(())
87     /// }
88     /// ```
from_path<P: AsRef<Path>>(&self, path: P) -> Result<Writer<File>>89     pub fn from_path<P: AsRef<Path>>(&self, path: P) -> Result<Writer<File>> {
90         Ok(Writer::new(self, File::create(path)?))
91     }
92 
93     /// Build a CSV writer from this configuration that writes data to `wtr`.
94     ///
95     /// Note that the CSV writer is buffered automatically, so you should not
96     /// wrap `wtr` in a buffered writer like `io::BufWriter`.
97     ///
98     /// # Example
99     ///
100     /// ```
101     /// use std::error::Error;
102     /// use csv::WriterBuilder;
103     ///
104     /// # fn main() { example().unwrap(); }
105     /// fn example() -> Result<(), Box<dyn Error>> {
106     ///     let mut wtr = WriterBuilder::new().from_writer(vec![]);
107     ///     wtr.write_record(&["a", "b", "c"])?;
108     ///     wtr.write_record(&["x", "y", "z"])?;
109     ///
110     ///     let data = String::from_utf8(wtr.into_inner()?)?;
111     ///     assert_eq!(data, "a,b,c\nx,y,z\n");
112     ///     Ok(())
113     /// }
114     /// ```
from_writer<W: io::Write>(&self, wtr: W) -> Writer<W>115     pub fn from_writer<W: io::Write>(&self, wtr: W) -> Writer<W> {
116         Writer::new(self, wtr)
117     }
118 
119     /// The field delimiter to use when writing CSV.
120     ///
121     /// The default is `b','`.
122     ///
123     /// # Example
124     ///
125     /// ```
126     /// use std::error::Error;
127     /// use csv::WriterBuilder;
128     ///
129     /// # fn main() { example().unwrap(); }
130     /// fn example() -> Result<(), Box<dyn Error>> {
131     ///     let mut wtr = WriterBuilder::new()
132     ///         .delimiter(b';')
133     ///         .from_writer(vec![]);
134     ///     wtr.write_record(&["a", "b", "c"])?;
135     ///     wtr.write_record(&["x", "y", "z"])?;
136     ///
137     ///     let data = String::from_utf8(wtr.into_inner()?)?;
138     ///     assert_eq!(data, "a;b;c\nx;y;z\n");
139     ///     Ok(())
140     /// }
141     /// ```
delimiter(&mut self, delimiter: u8) -> &mut WriterBuilder142     pub fn delimiter(&mut self, delimiter: u8) -> &mut WriterBuilder {
143         self.builder.delimiter(delimiter);
144         self
145     }
146 
147     /// Whether to write a header row before writing any other row.
148     ///
149     /// When this is enabled and the `serialize` method is used to write data
150     /// with something that contains field names (i.e., a struct), then a
151     /// header row is written containing the field names before any other row
152     /// is written.
153     ///
154     /// This option has no effect when using other methods to write rows. That
155     /// is, if you don't use `serialize`, then you must write your header row
156     /// explicitly if you want a header row.
157     ///
158     /// This is enabled by default.
159     ///
160     /// # Example: with headers
161     ///
162     /// This shows how the header will be automatically written from the field
163     /// names of a struct.
164     ///
165     /// ```
166     /// use std::error::Error;
167     ///
168     /// use csv::WriterBuilder;
169     /// use serde::Serialize;
170     ///
171     /// #[derive(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     /// Set the capacity (in bytes) of the internal buffer used in the CSV
474     /// writer. This defaults to a reasonable setting.
buffer_capacity(&mut self, capacity: usize) -> &mut WriterBuilder475     pub fn buffer_capacity(&mut self, capacity: usize) -> &mut WriterBuilder {
476         self.capacity = capacity;
477         self
478     }
479 }
480 
481 /// A already configured CSV writer.
482 ///
483 /// A CSV writer takes as input Rust values and writes those values in a valid
484 /// CSV format as output.
485 ///
486 /// While CSV writing is considerably easier than parsing CSV, a proper writer
487 /// will do a number of things for you:
488 ///
489 /// 1. Quote fields when necessary.
490 /// 2. Check that all records have the same number of fields.
491 /// 3. Write records with a single empty field correctly.
492 /// 4. Automatically serialize normal Rust types to CSV records. When that
493 ///    type is a struct, a header row is automatically written corresponding
494 ///    to the fields of that struct.
495 /// 5. Use buffering intelligently and otherwise avoid allocation. (This means
496 ///    that callers should not do their own buffering.)
497 ///
498 /// All of the above can be configured using a
499 /// [`WriterBuilder`](struct.WriterBuilder.html).
500 /// However, a `Writer` has a couple of convenience constructors (`from_path`
501 /// and `from_writer`) that use the default configuration.
502 ///
503 /// Note that the default configuration of a `Writer` uses `\n` for record
504 /// terminators instead of `\r\n` as specified by RFC 4180. Use the
505 /// `terminator` method on `WriterBuilder` to set the terminator to `\r\n` if
506 /// it's desired.
507 #[derive(Debug)]
508 pub struct Writer<W: io::Write> {
509     core: CoreWriter,
510     wtr: Option<W>,
511     buf: Buffer,
512     state: WriterState,
513 }
514 
515 #[derive(Debug)]
516 struct WriterState {
517     /// Whether the Serde serializer should attempt to write a header row.
518     header: HeaderState,
519     /// Whether inconsistent record lengths are allowed.
520     flexible: bool,
521     /// The number of fields writtein in the first record. This is compared
522     /// with `fields_written` on all subsequent records to check for
523     /// inconsistent record lengths.
524     first_field_count: Option<u64>,
525     /// The number of fields written in this record. This is used to report
526     /// errors for inconsistent record lengths if `flexible` is disabled.
527     fields_written: u64,
528     /// This is set immediately before flushing the buffer and then unset
529     /// immediately after flushing the buffer. This avoids flushing the buffer
530     /// twice if the inner writer panics.
531     panicked: bool,
532 }
533 
534 /// HeaderState encodes a small state machine for handling header writes.
535 #[derive(Debug)]
536 enum HeaderState {
537     /// Indicates that we should attempt to write a header.
538     Write,
539     /// Indicates that writing a header was attempt, and a header was written.
540     DidWrite,
541     /// Indicates that writing a header was attempted, but no headers were
542     /// written or the attempt failed.
543     DidNotWrite,
544     /// This state is used when headers are disabled. It cannot transition
545     /// to any other state.
546     None,
547 }
548 
549 /// A simple internal buffer for buffering writes.
550 ///
551 /// We need this because the `csv_core` APIs want to write into a `&mut [u8]`,
552 /// which is not available with the `std::io::BufWriter` API.
553 #[derive(Debug)]
554 struct Buffer {
555     /// The contents of the buffer.
556     buf: Vec<u8>,
557     /// The number of bytes written to the buffer.
558     len: usize,
559 }
560 
561 impl<W: io::Write> Drop for Writer<W> {
drop(&mut self)562     fn drop(&mut self) {
563         if self.wtr.is_some() && !self.state.panicked {
564             let _ = self.flush();
565         }
566     }
567 }
568 
569 impl Writer<File> {
570     /// Build a CSV writer with a default configuration that writes data to the
571     /// given file path. The file is truncated if it already exists.
572     ///
573     /// If there was a problem opening the file at the given path, then this
574     /// returns the corresponding error.
575     ///
576     /// # Example
577     ///
578     /// ```no_run
579     /// use std::error::Error;
580     /// use csv::Writer;
581     ///
582     /// # fn main() { example().unwrap(); }
583     /// fn example() -> Result<(), Box<dyn Error>> {
584     ///     let mut wtr = Writer::from_path("foo.csv")?;
585     ///     wtr.write_record(&["a", "b", "c"])?;
586     ///     wtr.write_record(&["x", "y", "z"])?;
587     ///     wtr.flush()?;
588     ///     Ok(())
589     /// }
590     /// ```
from_path<P: AsRef<Path>>(path: P) -> Result<Writer<File>>591     pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Writer<File>> {
592         WriterBuilder::new().from_path(path)
593     }
594 }
595 
596 impl<W: io::Write> Writer<W> {
new(builder: &WriterBuilder, wtr: W) -> Writer<W>597     fn new(builder: &WriterBuilder, wtr: W) -> Writer<W> {
598         let header_state = if builder.has_headers {
599             HeaderState::Write
600         } else {
601             HeaderState::None
602         };
603         Writer {
604             core: builder.builder.build(),
605             wtr: Some(wtr),
606             buf: Buffer { buf: vec![0; builder.capacity], len: 0 },
607             state: WriterState {
608                 header: header_state,
609                 flexible: builder.flexible,
610                 first_field_count: None,
611                 fields_written: 0,
612                 panicked: false,
613             },
614         }
615     }
616 
617     /// Build a CSV writer with a default configuration that writes data to
618     /// `wtr`.
619     ///
620     /// Note that the CSV writer is buffered automatically, so you should not
621     /// wrap `wtr` in a buffered writer like `io::BufWriter`.
622     ///
623     /// # Example
624     ///
625     /// ```
626     /// use std::error::Error;
627     /// use csv::Writer;
628     ///
629     /// # fn main() { example().unwrap(); }
630     /// fn example() -> Result<(), Box<dyn Error>> {
631     ///     let mut wtr = Writer::from_writer(vec![]);
632     ///     wtr.write_record(&["a", "b", "c"])?;
633     ///     wtr.write_record(&["x", "y", "z"])?;
634     ///
635     ///     let data = String::from_utf8(wtr.into_inner()?)?;
636     ///     assert_eq!(data, "a,b,c\nx,y,z\n");
637     ///     Ok(())
638     /// }
639     /// ```
from_writer(wtr: W) -> Writer<W>640     pub fn from_writer(wtr: W) -> Writer<W> {
641         WriterBuilder::new().from_writer(wtr)
642     }
643 
644     /// Serialize a single record using Serde.
645     ///
646     /// # Example
647     ///
648     /// This shows how to serialize normal Rust structs as CSV records. The
649     /// fields of the struct are used to write a header row automatically.
650     /// (Writing the header row automatically can be disabled by building the
651     /// CSV writer with a [`WriterBuilder`](struct.WriterBuilder.html) and
652     /// calling the `has_headers` method.)
653     ///
654     /// ```
655     /// use std::error::Error;
656     ///
657     /// use csv::Writer;
658     /// use serde::Serialize;
659     ///
660     /// #[derive(Serialize)]
661     /// struct Row<'a> {
662     ///     city: &'a str,
663     ///     country: &'a str,
664     ///     // Serde allows us to name our headers exactly,
665     ///     // even if they don't match our struct field names.
666     ///     #[serde(rename = "popcount")]
667     ///     population: u64,
668     /// }
669     ///
670     /// # fn main() { example().unwrap(); }
671     /// fn example() -> Result<(), Box<dyn Error>> {
672     ///     let mut wtr = Writer::from_writer(vec![]);
673     ///     wtr.serialize(Row {
674     ///         city: "Boston",
675     ///         country: "United States",
676     ///         population: 4628910,
677     ///     })?;
678     ///     wtr.serialize(Row {
679     ///         city: "Concord",
680     ///         country: "United States",
681     ///         population: 42695,
682     ///     })?;
683     ///
684     ///     let data = String::from_utf8(wtr.into_inner()?)?;
685     ///     assert_eq!(data, "\
686     /// city,country,popcount
687     /// Boston,United States,4628910
688     /// Concord,United States,42695
689     /// ");
690     ///     Ok(())
691     /// }
692     /// ```
693     ///
694     /// # Rules
695     ///
696     /// The behavior of `serialize` is fairly simple:
697     ///
698     /// 1. Nested containers (tuples, `Vec`s, structs, etc.) are always
699     ///    flattened (depth-first order).
700     ///
701     /// 2. If `has_headers` is `true` and the type contains field names, then
702     ///    a header row is automatically generated.
703     ///
704     /// However, some container types cannot be serialized, and if
705     /// `has_headers` is `true`, there are some additional restrictions on the
706     /// types that can be serialized. See below for details.
707     ///
708     /// For the purpose of this section, Rust types can be divided into three
709     /// categories: scalars, non-struct containers, and structs.
710     ///
711     /// ## Scalars
712     ///
713     /// Single values with no field names are written like the following. Note
714     /// that some of the outputs may be quoted, according to the selected
715     /// quoting style.
716     ///
717     /// | Name | Example Type | Example Value | Output |
718     /// | ---- | ---- | ---- | ---- |
719     /// | boolean | `bool` | `true` | `true` |
720     /// | integers | `i8`, `i16`, `i32`, `i64`, `i128`, `u8`, `u16`, `u32`, `u64`, `u128` | `5` | `5` |
721     /// | floats | `f32`, `f64` | `3.14` | `3.14` |
722     /// | character | `char` | `'☃'` | `☃` |
723     /// | string | `&str` | `"hi"` | `hi` |
724     /// | bytes | `&[u8]` | `b"hi"[..]` | `hi` |
725     /// | option | `Option` | `None` | *empty* |
726     /// | option |          | `Some(5)` | `5` |
727     /// | unit | `()` | `()` | *empty* |
728     /// | unit struct | `struct Foo;` | `Foo` | `Foo` |
729     /// | unit enum variant | `enum E { A, B }` | `E::A` | `A` |
730     /// | newtype struct | `struct Foo(u8);` | `Foo(5)` | `5` |
731     /// | newtype enum variant | `enum E { A(u8) }` | `E::A(5)` | `5` |
732     ///
733     /// Note that this table includes simple structs and enums. For example, to
734     /// serialize a field from either an integer or a float type, one can do
735     /// this:
736     ///
737     /// ```
738     /// use std::error::Error;
739     ///
740     /// use csv::Writer;
741     /// use serde::Serialize;
742     ///
743     /// #[derive(Serialize)]
744     /// struct Row {
745     ///     label: String,
746     ///     value: Value,
747     /// }
748     ///
749     /// #[derive(Serialize)]
750     /// enum Value {
751     ///     Integer(i64),
752     ///     Float(f64),
753     /// }
754     ///
755     /// # fn main() { example().unwrap(); }
756     /// fn example() -> Result<(), Box<dyn Error>> {
757     ///     let mut wtr = Writer::from_writer(vec![]);
758     ///     wtr.serialize(Row {
759     ///         label: "foo".to_string(),
760     ///         value: Value::Integer(3),
761     ///     })?;
762     ///     wtr.serialize(Row {
763     ///         label: "bar".to_string(),
764     ///         value: Value::Float(3.14),
765     ///     })?;
766     ///
767     ///     let data = String::from_utf8(wtr.into_inner()?)?;
768     ///     assert_eq!(data, "\
769     /// label,value
770     /// foo,3
771     /// bar,3.14
772     /// ");
773     ///     Ok(())
774     /// }
775     /// ```
776     ///
777     /// ## Non-Struct Containers
778     ///
779     /// Nested containers are flattened to their scalar components, with the
780     /// exeption of a few types that are not allowed:
781     ///
782     /// | Name | Example Type | Example Value | Output |
783     /// | ---- | ---- | ---- | ---- |
784     /// | sequence | `Vec<u8>` | `vec![1, 2, 3]` | `1,2,3` |
785     /// | tuple | `(u8, bool)` | `(5, true)` | `5,true` |
786     /// | tuple struct | `Foo(u8, bool)` | `Foo(5, true)` | `5,true` |
787     /// | tuple enum variant | `enum E { A(u8, bool) }` | `E::A(5, true)` | *error* |
788     /// | struct enum variant | `enum E { V { a: u8, b: bool } }` | `E::V { a: 5, b: true }` | *error* |
789     /// | map | `BTreeMap<K, V>` | `BTreeMap::new()` | *error* |
790     ///
791     /// ## Structs
792     ///
793     /// Like the other containers, structs are flattened to their scalar
794     /// components:
795     ///
796     /// | Name | Example Type | Example Value | Output |
797     /// | ---- | ---- | ---- | ---- |
798     /// | struct | `struct Foo { a: u8, b: bool }` | `Foo { a: 5, b: true }` | `5,true` |
799     ///
800     /// If `has_headers` is `false`, then there are no additional restrictions;
801     /// types can be nested arbitrarily. For example:
802     ///
803     /// ```
804     /// use std::error::Error;
805     ///
806     /// use csv::WriterBuilder;
807     /// use serde::Serialize;
808     ///
809     /// #[derive(Serialize)]
810     /// struct Row {
811     ///     label: String,
812     ///     values: Vec<f64>,
813     /// }
814     ///
815     /// # fn main() { example().unwrap(); }
816     /// fn example() -> Result<(), Box<dyn Error>> {
817     ///     let mut wtr = WriterBuilder::new()
818     ///         .has_headers(false)
819     ///         .from_writer(vec![]);
820     ///     wtr.serialize(Row {
821     ///         label: "foo".to_string(),
822     ///         values: vec![1.1234, 2.5678, 3.14],
823     ///     })?;
824     ///
825     ///     let data = String::from_utf8(wtr.into_inner()?)?;
826     ///     assert_eq!(data, "\
827     /// foo,1.1234,2.5678,3.14
828     /// ");
829     ///     Ok(())
830     /// }
831     /// ```
832     ///
833     /// However, if `has_headers` were enabled in the above example, then
834     /// serialization would return an error. Speficially, when `has_headers` is
835     /// `true`, there are two restrictions:
836     ///
837     /// 1. Named field values in structs must be scalars.
838     ///
839     /// 2. All scalars must be named field values in structs.
840     ///
841     /// Other than these two restrictions, types can be nested arbitrarily.
842     /// Here are a few examples:
843     ///
844     /// | Value | Header | Record |
845     /// | ---- | ---- | ---- |
846     /// | `(Foo { x: 5, y: 6 }, Bar { z: true })` | `x,y,z` | `5,6,true` |
847     /// | `vec![Foo { x: 5, y: 6 }, Foo { x: 7, y: 8 }]` | `x,y,x,y` | `5,6,7,8` |
848     /// | `(Foo { x: 5, y: 6 }, vec![Bar { z: Baz(true) }])` | `x,y,z` | `5,6,true` |
849     /// | `Foo { x: 5, y: (6, 7) }` | *error: restriction 1* | `5,6,7` |
850     /// | `(5, Foo { x: 6, y: 7 }` | *error: restriction 2* | `5,6,7` |
851     /// | `(Foo { x: 5, y: 6 }, true)` | *error: restriction 2* | `5,6,true` |
serialize<S: Serialize>(&mut self, record: S) -> Result<()>852     pub fn serialize<S: Serialize>(&mut self, record: S) -> Result<()> {
853         if let HeaderState::Write = self.state.header {
854             let wrote_header = serialize_header(self, &record)?;
855             if wrote_header {
856                 self.write_terminator()?;
857                 self.state.header = HeaderState::DidWrite;
858             } else {
859                 self.state.header = HeaderState::DidNotWrite;
860             };
861         }
862         serialize(self, &record)?;
863         self.write_terminator()?;
864         Ok(())
865     }
866 
867     /// Write a single record.
868     ///
869     /// This method accepts something that can be turned into an iterator that
870     /// yields elements that can be represented by a `&[u8]`.
871     ///
872     /// This may be called with an empty iterator, which will cause a record
873     /// terminator to be written. If no fields had been written, then a single
874     /// empty field is written before the terminator.
875     ///
876     /// # Example
877     ///
878     /// ```
879     /// use std::error::Error;
880     /// use csv::Writer;
881     ///
882     /// # fn main() { example().unwrap(); }
883     /// fn example() -> Result<(), Box<dyn Error>> {
884     ///     let mut wtr = Writer::from_writer(vec![]);
885     ///     wtr.write_record(&["a", "b", "c"])?;
886     ///     wtr.write_record(&["x", "y", "z"])?;
887     ///
888     ///     let data = String::from_utf8(wtr.into_inner()?)?;
889     ///     assert_eq!(data, "a,b,c\nx,y,z\n");
890     ///     Ok(())
891     /// }
892     /// ```
write_record<I, T>(&mut self, record: I) -> Result<()> where I: IntoIterator<Item = T>, T: AsRef<[u8]>,893     pub fn write_record<I, T>(&mut self, record: I) -> Result<()>
894     where
895         I: IntoIterator<Item = T>,
896         T: AsRef<[u8]>,
897     {
898         for field in record.into_iter() {
899             self.write_field_impl(field)?;
900         }
901         self.write_terminator()
902     }
903 
904     /// Write a single `ByteRecord`.
905     ///
906     /// This method accepts a borrowed `ByteRecord` and writes its contents
907     /// to the underlying writer.
908     ///
909     /// This is similar to `write_record` except that it specifically requires
910     /// a `ByteRecord`. This permits the writer to possibly write the record
911     /// more quickly than the more generic `write_record`.
912     ///
913     /// This may be called with an empty record, which will cause a record
914     /// terminator to be written. If no fields had been written, then a single
915     /// empty field is written before the terminator.
916     ///
917     /// # Example
918     ///
919     /// ```
920     /// use std::error::Error;
921     /// use csv::{ByteRecord, Writer};
922     ///
923     /// # fn main() { example().unwrap(); }
924     /// fn example() -> Result<(), Box<dyn Error>> {
925     ///     let mut wtr = Writer::from_writer(vec![]);
926     ///     wtr.write_byte_record(&ByteRecord::from(&["a", "b", "c"][..]))?;
927     ///     wtr.write_byte_record(&ByteRecord::from(&["x", "y", "z"][..]))?;
928     ///
929     ///     let data = String::from_utf8(wtr.into_inner()?)?;
930     ///     assert_eq!(data, "a,b,c\nx,y,z\n");
931     ///     Ok(())
932     /// }
933     /// ```
934     #[inline(never)]
write_byte_record(&mut self, record: &ByteRecord) -> Result<()>935     pub fn write_byte_record(&mut self, record: &ByteRecord) -> Result<()> {
936         if record.as_slice().is_empty() {
937             return self.write_record(record);
938         }
939         // The idea here is to find a fast path for shuffling our record into
940         // our buffer as quickly as possible. We do this because the underlying
941         // "core" CSV writer does a lot of book-keeping to maintain its state
942         // oriented API.
943         //
944         // The fast path occurs when we know our record will fit in whatever
945         // space we have left in our buffer. We can actually quickly compute
946         // the upper bound on the space required:
947         let upper_bound =
948             // The data itself plus the worst case: every byte is a quote.
949             (2 * record.as_slice().len())
950             // The number of field delimiters.
951             + (record.len().saturating_sub(1))
952             // The maximum number of quotes inserted around each field.
953             + (2 * record.len())
954             // The maximum number of bytes for the terminator.
955             + 2;
956         if self.buf.writable().len() < upper_bound {
957             return self.write_record(record);
958         }
959         let mut first = true;
960         for field in record.iter() {
961             if !first {
962                 self.buf.writable()[0] = self.core.get_delimiter();
963                 self.buf.written(1);
964             }
965             first = false;
966 
967             if !self.core.should_quote(field) {
968                 self.buf.writable()[..field.len()].copy_from_slice(field);
969                 self.buf.written(field.len());
970             } else {
971                 self.buf.writable()[0] = self.core.get_quote();
972                 self.buf.written(1);
973                 let (res, nin, nout) = csv_core::quote(
974                     field,
975                     self.buf.writable(),
976                     self.core.get_quote(),
977                     self.core.get_escape(),
978                     self.core.get_double_quote(),
979                 );
980                 debug_assert!(res == WriteResult::InputEmpty);
981                 debug_assert!(nin == field.len());
982                 self.buf.written(nout);
983                 self.buf.writable()[0] = self.core.get_quote();
984                 self.buf.written(1);
985             }
986         }
987         self.state.fields_written = record.len() as u64;
988         self.write_terminator_into_buffer()
989     }
990 
991     /// Write a single field.
992     ///
993     /// One should prefer using `write_record` over this method. It is provided
994     /// for cases where writing a field at a time is more convenient than
995     /// writing a record at a time.
996     ///
997     /// Note that if this API is used, `write_record` should be called with an
998     /// empty iterator to write a record terminator.
999     ///
1000     /// # Example
1001     ///
1002     /// ```
1003     /// use std::error::Error;
1004     /// use csv::Writer;
1005     ///
1006     /// # fn main() { example().unwrap(); }
1007     /// fn example() -> Result<(), Box<dyn Error>> {
1008     ///     let mut wtr = Writer::from_writer(vec![]);
1009     ///     wtr.write_field("a")?;
1010     ///     wtr.write_field("b")?;
1011     ///     wtr.write_field("c")?;
1012     ///     wtr.write_record(None::<&[u8]>)?;
1013     ///     wtr.write_field("x")?;
1014     ///     wtr.write_field("y")?;
1015     ///     wtr.write_field("z")?;
1016     ///     wtr.write_record(None::<&[u8]>)?;
1017     ///
1018     ///     let data = String::from_utf8(wtr.into_inner()?)?;
1019     ///     assert_eq!(data, "a,b,c\nx,y,z\n");
1020     ///     Ok(())
1021     /// }
1022     /// ```
write_field<T: AsRef<[u8]>>(&mut self, field: T) -> Result<()>1023     pub fn write_field<T: AsRef<[u8]>>(&mut self, field: T) -> Result<()> {
1024         self.write_field_impl(field)
1025     }
1026 
1027     /// Implementation of write_field.
1028     ///
1029     /// This is a separate method so we can force the compiler to inline it
1030     /// into write_record.
1031     #[inline(always)]
write_field_impl<T: AsRef<[u8]>>(&mut self, field: T) -> Result<()>1032     fn write_field_impl<T: AsRef<[u8]>>(&mut self, field: T) -> Result<()> {
1033         if self.state.fields_written > 0 {
1034             self.write_delimiter()?;
1035         }
1036         let mut field = field.as_ref();
1037         loop {
1038             let (res, nin, nout) = self.core.field(field, self.buf.writable());
1039             field = &field[nin..];
1040             self.buf.written(nout);
1041             match res {
1042                 WriteResult::InputEmpty => {
1043                     self.state.fields_written += 1;
1044                     return Ok(());
1045                 }
1046                 WriteResult::OutputFull => self.flush()?,
1047             }
1048         }
1049     }
1050 
1051     /// Flush the contents of the internal buffer to the underlying writer.
1052     ///
1053     /// If there was a problem writing to the underlying writer, then an error
1054     /// is returned.
1055     ///
1056     /// Note that this also flushes the underlying writer.
flush(&mut self) -> io::Result<()>1057     pub fn flush(&mut self) -> io::Result<()> {
1058         self.state.panicked = true;
1059         let result = self.wtr.as_mut().unwrap().write_all(self.buf.readable());
1060         self.state.panicked = false;
1061         result?;
1062         self.buf.clear();
1063         self.wtr.as_mut().unwrap().flush()?;
1064         Ok(())
1065     }
1066 
1067     /// Flush the contents of the internal buffer and return the underlying
1068     /// writer.
into_inner( mut self, ) -> result::Result<W, IntoInnerError<Writer<W>>>1069     pub fn into_inner(
1070         mut self,
1071     ) -> result::Result<W, IntoInnerError<Writer<W>>> {
1072         match self.flush() {
1073             Ok(()) => Ok(self.wtr.take().unwrap()),
1074             Err(err) => Err(IntoInnerError::new(self, err)),
1075         }
1076     }
1077 
1078     /// Write a CSV delimiter.
write_delimiter(&mut self) -> Result<()>1079     fn write_delimiter(&mut self) -> Result<()> {
1080         loop {
1081             let (res, nout) = self.core.delimiter(self.buf.writable());
1082             self.buf.written(nout);
1083             match res {
1084                 WriteResult::InputEmpty => return Ok(()),
1085                 WriteResult::OutputFull => self.flush()?,
1086             }
1087         }
1088     }
1089 
1090     /// Write a CSV terminator.
write_terminator(&mut self) -> Result<()>1091     fn write_terminator(&mut self) -> Result<()> {
1092         self.check_field_count()?;
1093         loop {
1094             let (res, nout) = self.core.terminator(self.buf.writable());
1095             self.buf.written(nout);
1096             match res {
1097                 WriteResult::InputEmpty => {
1098                     self.state.fields_written = 0;
1099                     return Ok(());
1100                 }
1101                 WriteResult::OutputFull => self.flush()?,
1102             }
1103         }
1104     }
1105 
1106     /// Write a CSV terminator that is guaranteed to fit into the current
1107     /// buffer.
1108     #[inline(never)]
write_terminator_into_buffer(&mut self) -> Result<()>1109     fn write_terminator_into_buffer(&mut self) -> Result<()> {
1110         self.check_field_count()?;
1111         match self.core.get_terminator() {
1112             csv_core::Terminator::CRLF => {
1113                 self.buf.writable()[0] = b'\r';
1114                 self.buf.writable()[1] = b'\n';
1115                 self.buf.written(2);
1116             }
1117             csv_core::Terminator::Any(b) => {
1118                 self.buf.writable()[0] = b;
1119                 self.buf.written(1);
1120             }
1121             _ => unreachable!(),
1122         }
1123         self.state.fields_written = 0;
1124         Ok(())
1125     }
1126 
check_field_count(&mut self) -> Result<()>1127     fn check_field_count(&mut self) -> Result<()> {
1128         if !self.state.flexible {
1129             match self.state.first_field_count {
1130                 None => {
1131                     self.state.first_field_count =
1132                         Some(self.state.fields_written);
1133                 }
1134                 Some(expected) if expected != self.state.fields_written => {
1135                     return Err(Error::new(ErrorKind::UnequalLengths {
1136                         pos: None,
1137                         expected_len: expected,
1138                         len: self.state.fields_written,
1139                     }))
1140                 }
1141                 Some(_) => {}
1142             }
1143         }
1144         Ok(())
1145     }
1146 }
1147 
1148 impl Buffer {
1149     /// Returns a slice of the buffer's current contents.
1150     ///
1151     /// The slice returned may be empty.
1152     #[inline]
readable(&self) -> &[u8]1153     fn readable(&self) -> &[u8] {
1154         &self.buf[..self.len]
1155     }
1156 
1157     /// Returns a mutable slice of the remaining space in this buffer.
1158     ///
1159     /// The slice returned may be empty.
1160     #[inline]
writable(&mut self) -> &mut [u8]1161     fn writable(&mut self) -> &mut [u8] {
1162         &mut self.buf[self.len..]
1163     }
1164 
1165     /// Indicates that `n` bytes have been written to this buffer.
1166     #[inline]
written(&mut self, n: usize)1167     fn written(&mut self, n: usize) {
1168         self.len += n;
1169     }
1170 
1171     /// Clear the buffer.
1172     #[inline]
clear(&mut self)1173     fn clear(&mut self) {
1174         self.len = 0;
1175     }
1176 }
1177 
1178 #[cfg(test)]
1179 mod tests {
1180     use serde::{serde_if_integer128, Serialize};
1181 
1182     use crate::byte_record::ByteRecord;
1183     use crate::error::ErrorKind;
1184     use crate::string_record::StringRecord;
1185 
1186     use super::{Writer, WriterBuilder};
1187 
wtr_as_string(wtr: Writer<Vec<u8>>) -> String1188     fn wtr_as_string(wtr: Writer<Vec<u8>>) -> String {
1189         String::from_utf8(wtr.into_inner().unwrap()).unwrap()
1190     }
1191 
1192     #[test]
one_record()1193     fn one_record() {
1194         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1195         wtr.write_record(&["a", "b", "c"]).unwrap();
1196 
1197         assert_eq!(wtr_as_string(wtr), "a,b,c\n");
1198     }
1199 
1200     #[test]
one_string_record()1201     fn one_string_record() {
1202         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1203         wtr.write_record(&StringRecord::from(vec!["a", "b", "c"])).unwrap();
1204 
1205         assert_eq!(wtr_as_string(wtr), "a,b,c\n");
1206     }
1207 
1208     #[test]
one_byte_record()1209     fn one_byte_record() {
1210         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1211         wtr.write_record(&ByteRecord::from(vec!["a", "b", "c"])).unwrap();
1212 
1213         assert_eq!(wtr_as_string(wtr), "a,b,c\n");
1214     }
1215 
1216     #[test]
raw_one_byte_record()1217     fn raw_one_byte_record() {
1218         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1219         wtr.write_byte_record(&ByteRecord::from(vec!["a", "b", "c"])).unwrap();
1220 
1221         assert_eq!(wtr_as_string(wtr), "a,b,c\n");
1222     }
1223 
1224     #[test]
one_empty_record()1225     fn one_empty_record() {
1226         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1227         wtr.write_record(&[""]).unwrap();
1228 
1229         assert_eq!(wtr_as_string(wtr), "\"\"\n");
1230     }
1231 
1232     #[test]
raw_one_empty_record()1233     fn raw_one_empty_record() {
1234         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1235         wtr.write_byte_record(&ByteRecord::from(vec![""])).unwrap();
1236 
1237         assert_eq!(wtr_as_string(wtr), "\"\"\n");
1238     }
1239 
1240     #[test]
two_empty_records()1241     fn two_empty_records() {
1242         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1243         wtr.write_record(&[""]).unwrap();
1244         wtr.write_record(&[""]).unwrap();
1245 
1246         assert_eq!(wtr_as_string(wtr), "\"\"\n\"\"\n");
1247     }
1248 
1249     #[test]
raw_two_empty_records()1250     fn raw_two_empty_records() {
1251         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1252         wtr.write_byte_record(&ByteRecord::from(vec![""])).unwrap();
1253         wtr.write_byte_record(&ByteRecord::from(vec![""])).unwrap();
1254 
1255         assert_eq!(wtr_as_string(wtr), "\"\"\n\"\"\n");
1256     }
1257 
1258     #[test]
unequal_records_bad()1259     fn unequal_records_bad() {
1260         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1261         wtr.write_record(&ByteRecord::from(vec!["a", "b", "c"])).unwrap();
1262         let err = wtr.write_record(&ByteRecord::from(vec!["a"])).unwrap_err();
1263         match *err.kind() {
1264             ErrorKind::UnequalLengths { ref pos, expected_len, len } => {
1265                 assert!(pos.is_none());
1266                 assert_eq!(expected_len, 3);
1267                 assert_eq!(len, 1);
1268             }
1269             ref x => {
1270                 panic!("expected UnequalLengths error, but got '{:?}'", x);
1271             }
1272         }
1273     }
1274 
1275     #[test]
raw_unequal_records_bad()1276     fn raw_unequal_records_bad() {
1277         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1278         wtr.write_byte_record(&ByteRecord::from(vec!["a", "b", "c"])).unwrap();
1279         let err =
1280             wtr.write_byte_record(&ByteRecord::from(vec!["a"])).unwrap_err();
1281         match *err.kind() {
1282             ErrorKind::UnequalLengths { ref pos, expected_len, len } => {
1283                 assert!(pos.is_none());
1284                 assert_eq!(expected_len, 3);
1285                 assert_eq!(len, 1);
1286             }
1287             ref x => {
1288                 panic!("expected UnequalLengths error, but got '{:?}'", x);
1289             }
1290         }
1291     }
1292 
1293     #[test]
unequal_records_ok()1294     fn unequal_records_ok() {
1295         let mut wtr = WriterBuilder::new().flexible(true).from_writer(vec![]);
1296         wtr.write_record(&ByteRecord::from(vec!["a", "b", "c"])).unwrap();
1297         wtr.write_record(&ByteRecord::from(vec!["a"])).unwrap();
1298         assert_eq!(wtr_as_string(wtr), "a,b,c\na\n");
1299     }
1300 
1301     #[test]
raw_unequal_records_ok()1302     fn raw_unequal_records_ok() {
1303         let mut wtr = WriterBuilder::new().flexible(true).from_writer(vec![]);
1304         wtr.write_byte_record(&ByteRecord::from(vec!["a", "b", "c"])).unwrap();
1305         wtr.write_byte_record(&ByteRecord::from(vec!["a"])).unwrap();
1306         assert_eq!(wtr_as_string(wtr), "a,b,c\na\n");
1307     }
1308 
1309     #[test]
serialize_with_headers()1310     fn serialize_with_headers() {
1311         #[derive(Serialize)]
1312         struct Row {
1313             foo: i32,
1314             bar: f64,
1315             baz: bool,
1316         }
1317 
1318         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1319         wtr.serialize(Row { foo: 42, bar: 42.5, baz: true }).unwrap();
1320         assert_eq!(wtr_as_string(wtr), "foo,bar,baz\n42,42.5,true\n");
1321     }
1322 
1323     #[test]
serialize_no_headers()1324     fn serialize_no_headers() {
1325         #[derive(Serialize)]
1326         struct Row {
1327             foo: i32,
1328             bar: f64,
1329             baz: bool,
1330         }
1331 
1332         let mut wtr =
1333             WriterBuilder::new().has_headers(false).from_writer(vec![]);
1334         wtr.serialize(Row { foo: 42, bar: 42.5, baz: true }).unwrap();
1335         assert_eq!(wtr_as_string(wtr), "42,42.5,true\n");
1336     }
1337 
1338     serde_if_integer128! {
1339         #[test]
1340         fn serialize_no_headers_128() {
1341             #[derive(Serialize)]
1342             struct Row {
1343                 foo: i128,
1344                 bar: f64,
1345                 baz: bool,
1346             }
1347 
1348             let mut wtr =
1349                 WriterBuilder::new().has_headers(false).from_writer(vec![]);
1350             wtr.serialize(Row {
1351                 foo: 9_223_372_036_854_775_808,
1352                 bar: 42.5,
1353                 baz: true,
1354             }).unwrap();
1355             assert_eq!(wtr_as_string(wtr), "9223372036854775808,42.5,true\n");
1356         }
1357     }
1358 
1359     #[test]
serialize_tuple()1360     fn serialize_tuple() {
1361         let mut wtr = WriterBuilder::new().from_writer(vec![]);
1362         wtr.serialize((true, 1.3, "hi")).unwrap();
1363         assert_eq!(wtr_as_string(wtr), "true,1.3,hi\n");
1364     }
1365 }
1366