1 /*! 2 `csv-core` provides a fast CSV reader and writer for use in a `no_std` context. 3 4 This crate will never use the standard library. `no_std` support is therefore 5 enabled by default. 6 7 If you're looking for more ergonomic CSV parsing routines, please use the 8 [`csv`](https://docs.rs/csv) crate. 9 10 # Overview 11 12 This crate has two primary APIs. The `Reader` API provides a CSV parser, and 13 the `Writer` API provides a CSV writer. 14 15 # Example: reading CSV 16 17 This example shows how to count the number of fields and records in CSV data. 18 19 ``` 20 use csv_core::{Reader, ReadFieldResult}; 21 22 let data = " 23 foo,bar,baz 24 a,b,c 25 xxx,yyy,zzz 26 "; 27 28 let mut rdr = Reader::new(); 29 let mut bytes = data.as_bytes(); 30 let mut count_fields = 0; 31 let mut count_records = 0; 32 loop { 33 // We skip handling the output since we don't need it for counting. 34 let (result, nin, _) = rdr.read_field(bytes, &mut [0; 1024]); 35 bytes = &bytes[nin..]; 36 match result { 37 ReadFieldResult::InputEmpty => {}, 38 ReadFieldResult::OutputFull => panic!("field too large"), 39 ReadFieldResult::Field { record_end } => { 40 count_fields += 1; 41 if record_end { 42 count_records += 1; 43 } 44 } 45 ReadFieldResult::End => break, 46 } 47 } 48 assert_eq!(3, count_records); 49 assert_eq!(9, count_fields); 50 ``` 51 52 # Example: writing CSV 53 54 This example shows how to use the `Writer` API to write valid CSV data. Proper 55 quoting is handled automatically. 56 57 ``` 58 use csv_core::Writer; 59 60 // This is where we'll write out CSV data. 61 let mut out = &mut [0; 1024]; 62 // The number of bytes we've written to `out`. 63 let mut nout = 0; 64 // Create a CSV writer with a default configuration. 65 let mut wtr = Writer::new(); 66 67 // Write a single field. Note that we ignore the `WriteResult` and the number 68 // of input bytes consumed since we're doing this by hand. 69 let (_, _, n) = wtr.field(&b"foo"[..], &mut out[nout..]); 70 nout += n; 71 72 // Write a delimiter and then another field that requires quotes. 73 let (_, n) = wtr.delimiter(&mut out[nout..]); 74 nout += n; 75 let (_, _, n) = wtr.field(&b"bar,baz"[..], &mut out[nout..]); 76 nout += n; 77 let (_, n) = wtr.terminator(&mut out[nout..]); 78 nout += n; 79 80 // Now write another record. 81 let (_, _, n) = wtr.field(&b"a \"b\" c"[..], &mut out[nout..]); 82 nout += n; 83 let (_, n) = wtr.delimiter(&mut out[nout..]); 84 nout += n; 85 let (_, _, n) = wtr.field(&b"quux"[..], &mut out[nout..]); 86 nout += n; 87 88 // We must always call finish once done writing. 89 // This ensures that any closing quotes are written. 90 let (_, n) = wtr.finish(&mut out[nout..]); 91 nout += n; 92 93 assert_eq!(&out[..nout], &b"\ 94 foo,\"bar,baz\" 95 \"a \"\"b\"\" c\",quux"[..]); 96 ``` 97 */ 98 99 #![deny(missing_docs)] 100 #![no_std] 101 102 pub use crate::reader::{ 103 ReadFieldNoCopyResult, ReadFieldResult, ReadRecordNoCopyResult, 104 ReadRecordResult, Reader, ReaderBuilder, 105 }; 106 pub use crate::writer::{ 107 is_non_numeric, quote, WriteResult, Writer, WriterBuilder, 108 }; 109 110 mod reader; 111 mod writer; 112 113 /// A record terminator. 114 /// 115 /// Use this to specify the record terminator while parsing CSV. The default is 116 /// CRLF, which treats `\r`, `\n` or `\r\n` as a single record terminator. 117 #[derive(Clone, Copy, Debug)] 118 pub enum Terminator { 119 /// Parses `\r`, `\n` or `\r\n` as a single record terminator. 120 CRLF, 121 /// Parses the byte given as a record terminator. 122 Any(u8), 123 /// Hints that destructuring should not be exhaustive. 124 /// 125 /// This enum may grow additional variants, so this makes sure clients 126 /// don't count on exhaustive matching. (Otherwise, adding a new variant 127 /// could break existing code.) 128 #[doc(hidden)] 129 __Nonexhaustive, 130 } 131 132 impl Terminator { 133 /// Checks whether the terminator is set to CRLF. is_crlf(&self) -> bool134 fn is_crlf(&self) -> bool { 135 match *self { 136 Terminator::CRLF => true, 137 Terminator::Any(_) => false, 138 _ => unreachable!(), 139 } 140 } 141 equals(&self, other: u8) -> bool142 fn equals(&self, other: u8) -> bool { 143 match *self { 144 Terminator::CRLF => other == b'\r' || other == b'\n', 145 Terminator::Any(b) => other == b, 146 _ => unreachable!(), 147 } 148 } 149 } 150 151 impl Default for Terminator { default() -> Terminator152 fn default() -> Terminator { 153 Terminator::CRLF 154 } 155 } 156 157 /// The quoting style to use when writing CSV data. 158 #[derive(Clone, Copy, Debug)] 159 pub enum QuoteStyle { 160 /// This puts quotes around every field. Always. 161 Always, 162 /// This puts quotes around fields only when necessary. 163 /// 164 /// They are necessary when fields contain a quote, delimiter or record 165 /// terminator. Quotes are also necessary when writing an empty record 166 /// (which is indistinguishable from a record with one empty field). 167 /// 168 /// This is the default. 169 Necessary, 170 /// This puts quotes around all fields that are non-numeric. Namely, when 171 /// writing a field that does not parse as a valid float or integer, then 172 /// quotes will be used even if they aren't strictly necessary. 173 NonNumeric, 174 /// This *never* writes quotes, even if it would produce invalid CSV data. 175 Never, 176 /// Hints that destructuring should not be exhaustive. 177 /// 178 /// This enum may grow additional variants, so this makes sure clients 179 /// don't count on exhaustive matching. (Otherwise, adding a new variant 180 /// could break existing code.) 181 #[doc(hidden)] 182 __Nonexhaustive, 183 } 184 185 impl Default for QuoteStyle { default() -> QuoteStyle186 fn default() -> QuoteStyle { 187 QuoteStyle::Necessary 188 } 189 } 190