csv_legacy/csv_legacy.rs
1//! A lightweight CSV parser and writer, compatible with `no_std` environments.
2//!
3//! # Quick start
4//!
5//! ```no_run
6//! use csv_legacy::Reader;
7//!
8//! let data = b"name,age\nAlice,30\nBob,25\n";
9//! let mut sum = 0u32;
10//!
11//! for result in Reader::new(data).rows() {
12//! let row = result?;
13//! // Access raw fields (including surrounding quotes) via indexing
14//! let name = &row[0]; // &str
15//! // Or via get_raw
16//! if let Some(name) = row.get_raw(0) {
17//! // name: &str
18//! }
19//! }
20//! # Ok::<_, csv_legacy::ReadError>(())
21//! ```
22//!
23//! Rows are yielded via [`Reader::rows`], which returns an iterator over
24//! [`Row`] values. Each [`Row`] owns its data and can outlive the reader.
25//!
26//! # Streaming from `std::io::Read`
27//!
28//! With the `std` feature (enabled by default), you can stream CSV data
29//! from any `std::io::Read` source without loading the entire input:
30//!
31//! ```no_run
32//! # use std::fs::File;
33//! # use csv_legacy::Reader;
34//! let file = File::open("data.csv")?;
35//! for result in Reader::from_reader(file).rows() {
36//! let row = result?;
37//! // ...
38//! }
39//! # Ok::<_, Box<dyn std::error::Error>>(())
40//! ```
41//!
42//! # Unescaped fields
43//!
44//! Use [`Row::fields`] to iterate over unescaped fields (quotes stripped,
45//! `""` resolved):
46//!
47//! ```no_run
48//! # use csv_legacy::Reader;
49//! let data = b"\"hello\",\"foo\"\"bar\"\n";
50//! for result in Reader::new(data).rows() {
51//! let row = result?;
52//! let fields: Vec<String> = row.fields().map(|f| f.into_owned()).collect();
53//! // fields: ["hello", "foo\"bar"]
54//! }
55//! # Ok::<_, csv_legacy::ReadError>(())
56//! ```
57//!
58//! # Writing CSV
59//!
60//! The [`Writer`] (requires `std`) writes CSV data to any `std::io::Write`
61//! sink, automatically quoting fields that contain delimiters, quotes,
62//! or newlines:
63//!
64//! ```no_run
65//! # use csv_legacy::Writer;
66//! let mut w = Writer::new(Vec::new());
67//! w.write_row(["name", "age", "city"])?;
68//! w.write_row(["Alice", "30", "New York, NY"])?;
69//! let bytes = w.into_inner()?;
70//! # Ok::<_, csv_legacy::WriteError>(())
71//! ```
72//!
73//! # Feature flags
74//!
75//! | Flag | Default | Description |
76//! |---------|---------|------------------------------------------|
77//! | `std` | on | Enables `From<std::io::Error>`, `Writer`, and [`Reader::from_reader`]. |
78//!
79//! # Errors
80//!
81//! Parsing errors are surfaced per row via [`ReadError`]. The error
82//! includes the line number and kind (unterminated quote, trailing
83//! content after a quoted field, invalid UTF-8, or I/O error).
84//!
85//! # `no_std` support
86//!
87//! Disable default features to use the crate in a `no_std` environment.
88//! The crate still requires `alloc` for its internal buffers.
89//!
90//! [`Reader::from_reader`]: Reader::from_reader
91//! [`Row::fields`]: Row::fields
92//!
93#![cfg_attr(not(feature = "std"), no_std)]
94
95extern crate alloc;
96
97#[cfg(feature = "std")]
98extern crate std;
99
100mod error;
101mod reader;
102
103#[cfg(feature = "std")]
104mod writer;
105
106pub use error::{ReadError, ReadErrorKind, WriteError};
107pub use reader::{Fields, Reader, Row, RowIntoIter, Rows};
108#[cfg(feature = "std")]
109pub use writer::Writer;