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