1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
//! CSV support for [Müsli].
//!
//! The API and semantics are modelled after the [`csv` crate], but CSV is
//! parsed and written by Müsli itself. Quoting follows [RFC 4180]: fields which
//! contain the delimiter, a quote or a line terminator are quoted, and quotes
//! inside of quoted fields are doubled up.
//!
//! The top-level value being encoded or decoded is a whole CSV document. A
//! sequence such as a [`Vec`] is a sequence of records, while anything else
//! such as a single struct is treated as a document with a single record.
//!
//! The supported records are:
//! * Structs with named fields, where each field is a column. If headers are
//! enabled, which is the default, the names of fields are written as a header
//! row and fields are matched by name against the header row when reading.
//! * Tuples, tuple structs and sequences, where each element is a column.
//! * Scalars, which are records with a single column.
//!
//! The values of fields can be integers, floats, booleans, strings, characters,
//! unit enum variants and [`Option`] where `None` is an empty field. Nested
//! containers such as maps, sequences or structs inside of a field raise an
//! error.
//!
//! CSV with headers is upgrade stable for structs:
//!
//! * ✔ Can tolerate missing fields if they are annotated with
//! `#[musli(default)]`.
//! * ✔ Can skip over unknown fields.
//!
//! [Müsli]: https://github.com/udoprog/musli
//! [RFC 4180]: https://www.rfc-editor.org/rfc/rfc4180
//! [`csv` crate]: https://docs.rs/csv
//! [`Vec`]: rust_alloc::vec::Vec
//!
//! ```
//! use musli::{Encode, Decode};
//!
//! #[derive(Debug, PartialEq, Encode, Decode)]
//! struct Version1 {
//! name: String,
//! }
//!
//! #[derive(Debug, PartialEq, Encode, Decode)]
//! struct Version2 {
//! name: String,
//! #[musli(default)]
//! age: Option<u32>,
//! }
//!
//! let version2 = musli::csv::to_string(&vec![
//! Version2 { name: String::from("Aristotle"), age: Some(61) },
//! Version2 { name: String::from("Plato, the philosopher"), age: None },
//! ])?;
//!
//! assert_eq!(version2, "name,age\nAristotle,61\n\"Plato, the philosopher\",\n");
//!
//! let version1: Vec<Version1> = musli::csv::from_str(&version2)?;
//!
//! assert_eq!(version1, vec![
//! Version1 { name: String::from("Aristotle") },
//! Version1 { name: String::from("Plato, the philosopher") },
//! ]);
//! # Ok::<_, musli::csv::Error>(())
//! ```
//!
//! <br>
//!
//! ## Headers
//!
//! When headers are enabled, the header row is written before the first
//! record. For structs it contains the names of their fields, and for other
//! kinds of records it contains the position of each field starting at `0`.
//! This differs from the `csv` crate, which doesn't write a header row for
//! records without field names, but means that documents written with headers
//! enabled can always be read back.
//!
//! When reading with headers enabled, the first row is always treated as a
//! header row.
//!
//! ```
//! use musli::csv::Encoding;
//! # use musli::csv::Error;
//!
//! const NO_HEADERS: Encoding = Encoding::new().with_headers(false);
//!
//! let points = vec![(1, 2), (3, 4)];
//!
//! assert_eq!(musli::csv::to_string(&points)?, "0,1\n1,2\n3,4\n");
//! assert_eq!(NO_HEADERS.to_string(&points)?, "1,2\n3,4\n");
//!
//! let decoded: Vec<(u32, u32)> = musli::csv::from_str("x,y\n1,2\n3,4\n")?;
//! assert_eq!(decoded, points);
//! # Ok::<_, Error>(())
//! ```
//!
//! Since columns are identified by the order in which fields are encoded,
//! every record has to encode its fields in the same order. Fields which are
//! conditionally skipped using `#[musli(skip_encoding_if = ..)]` are therefore
//! not supported, and maps can only be used as records if they always contain
//! the same keys in the same order.
//!
//! Like with the `csv` crate, an empty field is decoded as `None` for fields
//! which are an [`Option`], so `Some(String::new())` reads back as `None`.
//!
//! <br>
//!
//! ## Reading and writing records
//!
//! The record-oriented [`Reader`] and [`Writer`] decode or encode one record
//! at a time:
//!
//! ```
//! use musli::{Decode, Encode};
//! use musli::csv::Encoding;
//! # use musli::csv::Error;
//!
//! #[derive(Debug, PartialEq, Encode, Decode)]
//! struct Person<'a> {
//! name: &'a str,
//! age: u32,
//! }
//!
//! const ENCODING: Encoding = Encoding::new().with_delimiter(b';');
//!
//! let mut data = Vec::new();
//!
//! let mut writer = ENCODING.writer(&mut data);
//! writer.serialize(&Person { name: "Aristotle", age: 61 })?;
//! writer.serialize(&Person { name: "Plato", age: 80 })?;
//!
//! assert_eq!(data, b"name;age\nAristotle;61\nPlato;80\n");
//!
//! let mut reader = ENCODING.reader(&data);
//!
//! assert_eq!(reader.next_record()?, Some(Person { name: "Aristotle", age: 61 }));
//! assert_eq!(reader.next_record()?, Some(Person { name: "Plato", age: 80 }));
//! assert_eq!(reader.next_record::<Person<'_>>()?, None);
//! # Ok::<_, Error>(())
//! ```
/// Convenient result alias for use with `musli::csv`.
///
/// # Examples
///
/// ```
/// use musli::csv::{self, Result};
/// use musli::{Encode, Decode};
///
/// #[derive(Debug, PartialEq, Encode, Decode)]
/// struct Person {
/// name: String,
/// age: u32,
/// }
///
/// fn csv_roundtrip(people: &[Person]) -> Result<Vec<Person>> {
/// let csv_string = csv::to_string(people)?;
/// csv::from_str(&csv_string)
/// }
///
/// let original = vec![Person {
/// name: "Alice".to_string(),
/// age: 30
/// }];
///
/// let decoded = csv_roundtrip(&original)?;
/// assert_eq!(original, decoded);
/// # Ok::<_, musli::csv::Error>(())
/// ```
pub type Result<T, E = Error> = Result;
pub use Headers;
pub use to_writer;
pub use ;
pub use ;
pub use ;
pub use Error;
pub use ;
pub use DeserializeRecords;
pub use Reader;
pub use Writer;