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_buf()?, 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.flush_buf()?; 1059 self.wtr.as_mut().unwrap().flush()?; 1060 Ok(()) 1061 } 1062 1063 /// Flush the contents of the internal buffer to the underlying writer, 1064 /// without flushing the underlying writer. flush_buf(&mut self) -> io::Result<()>1065 fn flush_buf(&mut self) -> io::Result<()> { 1066 self.state.panicked = true; 1067 let result = self.wtr.as_mut().unwrap().write_all(self.buf.readable()); 1068 self.state.panicked = false; 1069 result?; 1070 self.buf.clear(); 1071 Ok(()) 1072 } 1073 1074 /// Flush the contents of the internal buffer and return the underlying 1075 /// writer. into_inner( mut self, ) -> result::Result<W, IntoInnerError<Writer<W>>>1076 pub fn into_inner( 1077 mut self, 1078 ) -> result::Result<W, IntoInnerError<Writer<W>>> { 1079 match self.flush() { 1080 Ok(()) => Ok(self.wtr.take().unwrap()), 1081 Err(err) => Err(IntoInnerError::new(self, err)), 1082 } 1083 } 1084 1085 /// Write a CSV delimiter. write_delimiter(&mut self) -> Result<()>1086 fn write_delimiter(&mut self) -> Result<()> { 1087 loop { 1088 let (res, nout) = self.core.delimiter(self.buf.writable()); 1089 self.buf.written(nout); 1090 match res { 1091 WriteResult::InputEmpty => return Ok(()), 1092 WriteResult::OutputFull => self.flush_buf()?, 1093 } 1094 } 1095 } 1096 1097 /// Write a CSV terminator. write_terminator(&mut self) -> Result<()>1098 fn write_terminator(&mut self) -> Result<()> { 1099 self.check_field_count()?; 1100 loop { 1101 let (res, nout) = self.core.terminator(self.buf.writable()); 1102 self.buf.written(nout); 1103 match res { 1104 WriteResult::InputEmpty => { 1105 self.state.fields_written = 0; 1106 return Ok(()); 1107 } 1108 WriteResult::OutputFull => self.flush_buf()?, 1109 } 1110 } 1111 } 1112 1113 /// Write a CSV terminator that is guaranteed to fit into the current 1114 /// buffer. 1115 #[inline(never)] write_terminator_into_buffer(&mut self) -> Result<()>1116 fn write_terminator_into_buffer(&mut self) -> Result<()> { 1117 self.check_field_count()?; 1118 match self.core.get_terminator() { 1119 csv_core::Terminator::CRLF => { 1120 self.buf.writable()[0] = b'\r'; 1121 self.buf.writable()[1] = b'\n'; 1122 self.buf.written(2); 1123 } 1124 csv_core::Terminator::Any(b) => { 1125 self.buf.writable()[0] = b; 1126 self.buf.written(1); 1127 } 1128 _ => unreachable!(), 1129 } 1130 self.state.fields_written = 0; 1131 Ok(()) 1132 } 1133 check_field_count(&mut self) -> Result<()>1134 fn check_field_count(&mut self) -> Result<()> { 1135 if !self.state.flexible { 1136 match self.state.first_field_count { 1137 None => { 1138 self.state.first_field_count = 1139 Some(self.state.fields_written); 1140 } 1141 Some(expected) if expected != self.state.fields_written => { 1142 return Err(Error::new(ErrorKind::UnequalLengths { 1143 pos: None, 1144 expected_len: expected, 1145 len: self.state.fields_written, 1146 })) 1147 } 1148 Some(_) => {} 1149 } 1150 } 1151 Ok(()) 1152 } 1153 } 1154 1155 impl Buffer { 1156 /// Returns a slice of the buffer's current contents. 1157 /// 1158 /// The slice returned may be empty. 1159 #[inline] readable(&self) -> &[u8]1160 fn readable(&self) -> &[u8] { 1161 &self.buf[..self.len] 1162 } 1163 1164 /// Returns a mutable slice of the remaining space in this buffer. 1165 /// 1166 /// The slice returned may be empty. 1167 #[inline] writable(&mut self) -> &mut [u8]1168 fn writable(&mut self) -> &mut [u8] { 1169 &mut self.buf[self.len..] 1170 } 1171 1172 /// Indicates that `n` bytes have been written to this buffer. 1173 #[inline] written(&mut self, n: usize)1174 fn written(&mut self, n: usize) { 1175 self.len += n; 1176 } 1177 1178 /// Clear the buffer. 1179 #[inline] clear(&mut self)1180 fn clear(&mut self) { 1181 self.len = 0; 1182 } 1183 } 1184 1185 #[cfg(test)] 1186 mod tests { 1187 use serde::{serde_if_integer128, Serialize}; 1188 1189 use std::io::{self, Write}; 1190 1191 use crate::byte_record::ByteRecord; 1192 use crate::error::ErrorKind; 1193 use crate::string_record::StringRecord; 1194 1195 use super::{Writer, WriterBuilder}; 1196 wtr_as_string(wtr: Writer<Vec<u8>>) -> String1197 fn wtr_as_string(wtr: Writer<Vec<u8>>) -> String { 1198 String::from_utf8(wtr.into_inner().unwrap()).unwrap() 1199 } 1200 1201 #[test] one_record()1202 fn one_record() { 1203 let mut wtr = WriterBuilder::new().from_writer(vec![]); 1204 wtr.write_record(&["a", "b", "c"]).unwrap(); 1205 1206 assert_eq!(wtr_as_string(wtr), "a,b,c\n"); 1207 } 1208 1209 #[test] one_string_record()1210 fn one_string_record() { 1211 let mut wtr = WriterBuilder::new().from_writer(vec![]); 1212 wtr.write_record(&StringRecord::from(vec!["a", "b", "c"])).unwrap(); 1213 1214 assert_eq!(wtr_as_string(wtr), "a,b,c\n"); 1215 } 1216 1217 #[test] one_byte_record()1218 fn one_byte_record() { 1219 let mut wtr = WriterBuilder::new().from_writer(vec![]); 1220 wtr.write_record(&ByteRecord::from(vec!["a", "b", "c"])).unwrap(); 1221 1222 assert_eq!(wtr_as_string(wtr), "a,b,c\n"); 1223 } 1224 1225 #[test] raw_one_byte_record()1226 fn raw_one_byte_record() { 1227 let mut wtr = WriterBuilder::new().from_writer(vec![]); 1228 wtr.write_byte_record(&ByteRecord::from(vec!["a", "b", "c"])).unwrap(); 1229 1230 assert_eq!(wtr_as_string(wtr), "a,b,c\n"); 1231 } 1232 1233 #[test] one_empty_record()1234 fn one_empty_record() { 1235 let mut wtr = WriterBuilder::new().from_writer(vec![]); 1236 wtr.write_record(&[""]).unwrap(); 1237 1238 assert_eq!(wtr_as_string(wtr), "\"\"\n"); 1239 } 1240 1241 #[test] raw_one_empty_record()1242 fn raw_one_empty_record() { 1243 let mut wtr = WriterBuilder::new().from_writer(vec![]); 1244 wtr.write_byte_record(&ByteRecord::from(vec![""])).unwrap(); 1245 1246 assert_eq!(wtr_as_string(wtr), "\"\"\n"); 1247 } 1248 1249 #[test] two_empty_records()1250 fn two_empty_records() { 1251 let mut wtr = WriterBuilder::new().from_writer(vec![]); 1252 wtr.write_record(&[""]).unwrap(); 1253 wtr.write_record(&[""]).unwrap(); 1254 1255 assert_eq!(wtr_as_string(wtr), "\"\"\n\"\"\n"); 1256 } 1257 1258 #[test] raw_two_empty_records()1259 fn raw_two_empty_records() { 1260 let mut wtr = WriterBuilder::new().from_writer(vec![]); 1261 wtr.write_byte_record(&ByteRecord::from(vec![""])).unwrap(); 1262 wtr.write_byte_record(&ByteRecord::from(vec![""])).unwrap(); 1263 1264 assert_eq!(wtr_as_string(wtr), "\"\"\n\"\"\n"); 1265 } 1266 1267 #[test] unequal_records_bad()1268 fn unequal_records_bad() { 1269 let mut wtr = WriterBuilder::new().from_writer(vec![]); 1270 wtr.write_record(&ByteRecord::from(vec!["a", "b", "c"])).unwrap(); 1271 let err = wtr.write_record(&ByteRecord::from(vec!["a"])).unwrap_err(); 1272 match *err.kind() { 1273 ErrorKind::UnequalLengths { ref pos, expected_len, len } => { 1274 assert!(pos.is_none()); 1275 assert_eq!(expected_len, 3); 1276 assert_eq!(len, 1); 1277 } 1278 ref x => { 1279 panic!("expected UnequalLengths error, but got '{:?}'", x); 1280 } 1281 } 1282 } 1283 1284 #[test] raw_unequal_records_bad()1285 fn raw_unequal_records_bad() { 1286 let mut wtr = WriterBuilder::new().from_writer(vec![]); 1287 wtr.write_byte_record(&ByteRecord::from(vec!["a", "b", "c"])).unwrap(); 1288 let err = 1289 wtr.write_byte_record(&ByteRecord::from(vec!["a"])).unwrap_err(); 1290 match *err.kind() { 1291 ErrorKind::UnequalLengths { ref pos, expected_len, len } => { 1292 assert!(pos.is_none()); 1293 assert_eq!(expected_len, 3); 1294 assert_eq!(len, 1); 1295 } 1296 ref x => { 1297 panic!("expected UnequalLengths error, but got '{:?}'", x); 1298 } 1299 } 1300 } 1301 1302 #[test] unequal_records_ok()1303 fn unequal_records_ok() { 1304 let mut wtr = WriterBuilder::new().flexible(true).from_writer(vec![]); 1305 wtr.write_record(&ByteRecord::from(vec!["a", "b", "c"])).unwrap(); 1306 wtr.write_record(&ByteRecord::from(vec!["a"])).unwrap(); 1307 assert_eq!(wtr_as_string(wtr), "a,b,c\na\n"); 1308 } 1309 1310 #[test] raw_unequal_records_ok()1311 fn raw_unequal_records_ok() { 1312 let mut wtr = WriterBuilder::new().flexible(true).from_writer(vec![]); 1313 wtr.write_byte_record(&ByteRecord::from(vec!["a", "b", "c"])).unwrap(); 1314 wtr.write_byte_record(&ByteRecord::from(vec!["a"])).unwrap(); 1315 assert_eq!(wtr_as_string(wtr), "a,b,c\na\n"); 1316 } 1317 1318 #[test] full_buffer_should_not_flush_underlying()1319 fn full_buffer_should_not_flush_underlying() { 1320 struct MarkWriteAndFlush(Vec<u8>); 1321 1322 impl MarkWriteAndFlush { 1323 fn to_str(self) -> String { 1324 String::from_utf8(self.0).unwrap() 1325 } 1326 } 1327 1328 impl Write for MarkWriteAndFlush { 1329 fn write(&mut self, data: &[u8]) -> io::Result<usize> { 1330 self.0.write(b">")?; 1331 let written = self.0.write(data)?; 1332 self.0.write(b"<")?; 1333 1334 Ok(written) 1335 } 1336 1337 fn flush(&mut self) -> io::Result<()> { 1338 self.0.write(b"!")?; 1339 Ok(()) 1340 } 1341 } 1342 1343 let underlying = MarkWriteAndFlush(vec![]); 1344 let mut wtr = 1345 WriterBuilder::new().buffer_capacity(4).from_writer(underlying); 1346 1347 wtr.write_byte_record(&ByteRecord::from(vec!["a", "b"])).unwrap(); 1348 wtr.write_byte_record(&ByteRecord::from(vec!["c", "d"])).unwrap(); 1349 wtr.flush().unwrap(); 1350 wtr.write_byte_record(&ByteRecord::from(vec!["e", "f"])).unwrap(); 1351 1352 let got = wtr.into_inner().unwrap().to_str(); 1353 1354 // As the buffer size is 4 we should write each record separately, and 1355 // flush when explicitly called and implictly in into_inner. 1356 assert_eq!(got, ">a,b\n<>c,d\n<!>e,f\n<!"); 1357 } 1358 1359 #[test] serialize_with_headers()1360 fn serialize_with_headers() { 1361 #[derive(Serialize)] 1362 struct Row { 1363 foo: i32, 1364 bar: f64, 1365 baz: bool, 1366 } 1367 1368 let mut wtr = WriterBuilder::new().from_writer(vec![]); 1369 wtr.serialize(Row { foo: 42, bar: 42.5, baz: true }).unwrap(); 1370 assert_eq!(wtr_as_string(wtr), "foo,bar,baz\n42,42.5,true\n"); 1371 } 1372 1373 #[test] serialize_no_headers()1374 fn serialize_no_headers() { 1375 #[derive(Serialize)] 1376 struct Row { 1377 foo: i32, 1378 bar: f64, 1379 baz: bool, 1380 } 1381 1382 let mut wtr = 1383 WriterBuilder::new().has_headers(false).from_writer(vec![]); 1384 wtr.serialize(Row { foo: 42, bar: 42.5, baz: true }).unwrap(); 1385 assert_eq!(wtr_as_string(wtr), "42,42.5,true\n"); 1386 } 1387 1388 serde_if_integer128! { 1389 #[test] 1390 fn serialize_no_headers_128() { 1391 #[derive(Serialize)] 1392 struct Row { 1393 foo: i128, 1394 bar: f64, 1395 baz: bool, 1396 } 1397 1398 let mut wtr = 1399 WriterBuilder::new().has_headers(false).from_writer(vec![]); 1400 wtr.serialize(Row { 1401 foo: 9_223_372_036_854_775_808, 1402 bar: 42.5, 1403 baz: true, 1404 }).unwrap(); 1405 assert_eq!(wtr_as_string(wtr), "9223372036854775808,42.5,true\n"); 1406 } 1407 } 1408 1409 #[test] serialize_tuple()1410 fn serialize_tuple() { 1411 let mut wtr = WriterBuilder::new().from_writer(vec![]); 1412 wtr.serialize((true, 1.3, "hi")).unwrap(); 1413 assert_eq!(wtr_as_string(wtr), "true,1.3,hi\n"); 1414 } 1415 } 1416