Skip to main content

deser_csv/
ser.rs

1use alloc::format;
2use alloc::string::String;
3use alloc::string::ToString;
4use alloc::vec;
5use alloc::vec::Vec;
6use core::fmt::{self, Write as _};
7
8use deser_core::ext::Number;
9use deser_core::ser::SerializeRef;
10use deser_core::ser::{self, EventSink, SerializeDriver};
11use deser_core::{Atom, BytesFormat, Error, ErrorKind, Event, Serialize, State};
12
13use crate::parser::{Dialect, load_u32, load_u64};
14
15/// Reads sixteen bytes at `pos`.
16#[inline(always)]
17fn load_u128(bytes: &[u8], pos: usize) -> u128 {
18    u128::from_ne_bytes(*bytes[pos..].first_chunk().unwrap())
19}
20use crate::{Escape, Nulls, QuoteStyle, Terminator};
21
22/// Configures how values are serialized into delimited text.
23///
24/// The value is a sequence of records.  Records are maps (for instance
25/// structs), the keys of the first record are the names of the columns
26/// which are written first (see [`set_headers`](Self::set_headers)), or sequences
27/// (for instance tuples).  Fields are written in the order of the names,
28/// missing fields are empty and keys that are not a column are an error.
29/// Fields cannot hold maps or sequences (see
30/// [`Separated`](deser_core::adapters::Separated) for lists in a field).
31///
32/// Numbers are written with the shortest text that reads back as the same
33/// value, booleans as `true` and `false`, null as an empty field (see
34/// [`set_nulls`](Self::set_nulls)) and bytes as base64 (or the
35/// [`BytesFormat`](deser_core::BytesFormat) of the context).  Fields are quoted if necessary (see
36/// [`set_quote_style`](Self::set_quote_style)).
37///
38/// ```
39/// use deser_csv::{SerializerConfig, Terminator};
40///
41/// #[derive(deser::Serialize)]
42/// struct Row {
43///     name: &'static str,
44///     note: Option<&'static str>,
45/// }
46///
47/// let rows =
48///     [Row { name: "a", note: Some("x;y") }, Row { name: "b", note: None }];
49/// let config =
50///     SerializerConfig::builder().delimiter(b';').terminator(Terminator::CrLf).build();
51/// assert_eq!(
52///     config.to_string(&rows).unwrap(),
53///     "name;note\r\na;\"x;y\"\r\nb;\r\n"
54/// );
55/// ```
56#[derive(Debug, Clone, PartialEq, Eq)]
57pub struct SerializerConfig {
58    delimiter: u8,
59    quote: Option<u8>,
60    double_quote: bool,
61    escape: Escape,
62    terminator: Terminator,
63    quote_style: QuoteStyle,
64    headers: bool,
65    columns: Option<&'static [&'static str]>,
66    nulls: Nulls,
67    flexible: bool,
68    escape_formulas: bool,
69    context: deser_core::Context,
70}
71
72impl Default for SerializerConfig {
73    fn default() -> SerializerConfig {
74        SerializerConfig::new()
75    }
76}
77
78impl SerializerConfig {
79    /// Creates the default configuration (CSV).
80    pub const fn new() -> SerializerConfig {
81        SerializerConfig {
82            delimiter: b',',
83            quote: Some(b'"'),
84            double_quote: true,
85            escape: Escape::None,
86            terminator: Terminator::Newline,
87            quote_style: QuoteStyle::Necessary,
88            headers: true,
89            columns: None,
90            nulls: Nulls::None,
91            flexible: false,
92            escape_formulas: false,
93            context: deser_core::Context::new(),
94        }
95    }
96
97    /// Returns a builder for the configuration (see [`SerializerConfigBuilder`]).
98    pub const fn builder() -> SerializerConfigBuilder {
99        SerializerConfigBuilder::new()
100    }
101
102    /// Returns a builder that starts with this configuration.
103    pub const fn into_builder(self) -> SerializerConfigBuilder {
104        SerializerConfigBuilder { value: self }
105    }
106
107    /// Sets the context the values are serialized in.
108    ///
109    /// The values of the context are the defaults of the extension values
110    /// of the state (see [`Context`](deser_core::Context)), for instance
111    /// the [`BytesFormat`](deser_core::BytesFormat).  The serializers and
112    /// writers created with the configuration use this context.  A context set on
113    /// the driver takes precedence.
114    pub fn set_context(&mut self, context: deser_core::Context) {
115        self.context = context;
116    }
117
118    /// Returns the context the values are serialized in.
119    pub fn context(&self) -> &deser_core::Context {
120        &self.context
121    }
122
123    /// Gives the context to a driver which has none.
124    #[inline]
125    fn apply_context(&self, driver: &mut SerializeDriver<'_>) {
126        if !self.context.is_empty() {
127            driver.set_default_context(self.context.clone());
128        }
129    }
130
131    /// Creates the configuration for tab separated values.
132    ///
133    /// This is the counterpart of
134    /// [`DeserializerConfig::tsv`](crate::DeserializerConfig::tsv): fields
135    /// are separated by tabs, special characters are escaped with
136    /// backslashes and null is `\N`.
137    ///
138    /// ```
139    /// let rows = vec![("a\tb", Some(1)), ("c", None)];
140    /// let tsv = deser_csv::SerializerConfig::tsv().to_string(&rows).unwrap();
141    /// assert_eq!(tsv, "a\\tb\t1\nc\t\\N\n");
142    /// ```
143    pub const fn tsv() -> SerializerConfig {
144        let mut config = SerializerConfig::new();
145        config.set_delimiter(b'\t');
146        config.set_quote(None);
147        config.set_escape(Escape::Backslash);
148        config.set_nulls(Nulls::Text("\\N"));
149        config
150    }
151
152    /// Sets the character that separates fields (`,` by default).
153    pub const fn set_delimiter(&mut self, delimiter: u8) {
154        self.delimiter = delimiter;
155    }
156
157    /// Sets the character that quotes fields (`"` by default).
158    ///
159    /// Without quotes, fields that need them are an error (unless they
160    /// can be escaped, see [`set_escape`](Self::set_escape)).
161    pub const fn set_quote(&mut self, quote: Option<u8>) {
162        self.quote = quote;
163    }
164
165    /// Sets if quotes in quoted fields are doubled (`true` by default).
166    ///
167    /// Otherwise they are escaped (see [`set_escape`](Self::set_escape)).
168    pub const fn set_double_quote(&mut self, yes: bool) {
169        self.double_quote = yes;
170    }
171
172    /// Sets how characters are escaped (not at all by default).
173    ///
174    /// With an escape character, special characters in unquoted fields are
175    /// escaped instead of quoting the field.
176    pub const fn set_escape(&mut self, escape: Escape) {
177        self.escape = escape;
178    }
179
180    /// Sets the line ending (`\n` by default, see [`Terminator`]).
181    pub const fn set_terminator(&mut self, terminator: Terminator) {
182        self.terminator = terminator;
183    }
184
185    /// Sets when fields are quoted ([`QuoteStyle::Necessary`] by default).
186    pub const fn set_quote_style(&mut self, style: QuoteStyle) {
187        self.quote_style = style;
188    }
189
190    /// Sets if the names of the columns are written before the first
191    /// record (`true` by default).
192    ///
193    /// The names are the keys of the first record (or the given columns,
194    /// see [`set_columns`](Self::set_columns)).  Records that are sequences have no
195    /// names.
196    pub const fn set_headers(&mut self, yes: bool) {
197        self.headers = yes;
198    }
199
200    /// Sets the names of the columns (by default they are the keys of the
201    /// first record).
202    ///
203    /// This is needed if the first record does not have all keys, for
204    /// instance because records are enums or skip fields.  Fields are
205    /// written in the order of the columns, missing fields are empty.
206    ///
207    /// ```
208    /// #[derive(deser::Serialize)]
209    /// #[deser(tag = "kind", rename_all = "lowercase")]
210    /// enum Shape {
211    ///     Circle { radius: f64 },
212    ///     Rect { width: f64, height: f64 },
213    /// }
214    ///
215    /// let shapes = [
216    ///     Shape::Circle { radius: 1.0 },
217    ///     Shape::Rect { width: 2.0, height: 3.0 },
218    /// ];
219    /// let config = deser_csv::SerializerConfig::builder()
220    ///     .columns(&["kind", "radius", "width", "height"]).build();
221    /// assert_eq!(
222    ///     config.to_string(&shapes).unwrap(),
223    ///     "kind,radius,width,height\ncircle,1.0,,\nrect,,2.0,3.0\n"
224    /// );
225    /// ```
226    pub const fn set_columns(&mut self, names: &'static [&'static str]) {
227        self.columns = Some(names);
228    }
229
230    /// Sets how null is written ([`Nulls::None`] by default).
231    ///
232    /// Null is written as an empty field unless it's [`Nulls::Text`].
233    /// Strings that would read back as null are quoted (the empty string
234    /// with [`Nulls::Empty`]).
235    pub const fn set_nulls(&mut self, nulls: Nulls) {
236        self.nulls = nulls;
237    }
238
239    /// Sets if records can have a different number of fields (`false` by
240    /// default).
241    pub const fn set_flexible(&mut self, yes: bool) {
242        self.flexible = yes;
243    }
244
245    /// Sets if strings that spreadsheets would run as formulas are escaped
246    /// (`false` by default).
247    ///
248    /// Spreadsheets run fields that start with `=`, `+`, `-` or `@` (or a
249    /// tab or carriage return) as formulas, which is a problem when a file
250    /// contains data of untrusted users (["CSV
251    /// injection"](https://owasp.org/www-community/attacks/CSV_Injection)).
252    /// With this enabled, such strings are prefixed with `'` and quoted
253    /// (as recommended by OWASP).  Numbers are written as they are.
254    ///
255    /// ```
256    /// let config = deser_csv::SerializerConfig::builder().escape_formulas(true).build();
257    /// let rows = vec![("=1+2", -3)];
258    /// assert_eq!(config.to_string(&rows).unwrap(), "\"'=1+2\",-3\n");
259    /// ```
260    pub const fn set_escape_formulas(&mut self, yes: bool) {
261        self.escape_formulas = yes;
262    }
263
264    /// Serializes the records of a value.
265    ///
266    /// The value has to be a sequence of records.
267    pub fn to_string<T: Serialize + ?Sized>(&self, value: &T) -> Result<String, Error> {
268        self.to_string_ref(SerializeRef::new(&value))
269    }
270
271    /// Serializes the records of a value with a configured driver.
272    ///
273    /// The callback is invoked with the driver before the serialization
274    /// starts, for instance to add [`Layer`](deser_core::ser::Layer)s.
275    pub fn to_string_with<F, T: Serialize + ?Sized>(
276        &self,
277        value: &T,
278        setup: F,
279    ) -> Result<String, Error>
280    where
281        F: FnOnce(&mut SerializeDriver<'_>),
282    {
283        let mut driver = SerializeDriver::new(&value);
284        setup(&mut driver);
285        self.apply_context(&mut driver);
286        let mut out = Vec::new();
287        self.write_whole(&mut WriterState::default(), &mut driver, true, &mut out)?;
288        Ok(into_string(out))
289    }
290
291    /// Serializes a value whose type is erased (see
292    /// [`to_string`](Self::to_string)).
293    ///
294    /// This is not generic: the code that exists for every type only
295    /// erases it.
296    fn to_string_ref(&self, value: SerializeRef<'_>) -> Result<String, Error> {
297        let mut driver = SerializeDriver::from_ref(value);
298        self.apply_context(&mut driver);
299        let mut out = Vec::new();
300        self.write_whole(&mut WriterState::default(), &mut driver, true, &mut out)?;
301        Ok(into_string(out))
302    }
303
304    /// Serializes the records (or the record) of a driver and appends them
305    /// to the output.
306    ///
307    /// Only the output is changed if this fails.  Between records, the
308    /// driver is paused once the output holds at least `limit` bytes and
309    /// `false` is returned (the next call continues with the next record).
310    pub(crate) fn write(
311        &self,
312        state: &mut WriterState,
313        driver: &mut SerializeDriver<'_>,
314        document: bool,
315        out: &mut Vec<u8>,
316        limit: usize,
317    ) -> Result<bool, Error> {
318        let drive: DriveFn = if limit == usize::MAX {
319            drive_whole
320        } else {
321            drive_partial
322        };
323        self.write_with(state, driver, document, out, limit, drive)
324    }
325
326    /// Serializes the records of a driver at once and appends them to the
327    /// output (see `write`).
328    ///
329    /// Unlike `write` this does not refer to the pausable instance of the
330    /// driver which is only needed by stream serializers.
331    pub(crate) fn write_whole(
332        &self,
333        state: &mut WriterState,
334        driver: &mut SerializeDriver<'_>,
335        document: bool,
336        out: &mut Vec<u8>,
337    ) -> Result<(), Error> {
338        self.write_with(state, driver, document, out, usize::MAX, drive_whole)
339            .map(|_| ())
340    }
341
342    /// Implements `write` with the function that drives the driver.
343    fn write_with(
344        &self,
345        state: &mut WriterState,
346        driver: &mut SerializeDriver<'_>,
347        document: bool,
348        out: &mut Vec<u8>,
349        limit: usize,
350        drive: DriveFn,
351    ) -> Result<bool, Error> {
352        let dialect = match state.dialect {
353            Some(ref dialect) => dialect,
354            None => state.dialect.insert(Dialect::new(
355                self.delimiter,
356                self.quote,
357                self.double_quote,
358                self.escape,
359                self.terminator,
360                None,
361            )?),
362        };
363        let mut writer = RecordWriter {
364            encoder: FieldEncoder {
365                config: self,
366                dialect,
367                bytes: BytesFormat::of(driver.state()),
368                plain: matches!(self.quote_style, QuoteStyle::Necessary | QuoteStyle::Never)
369                    && self.nulls == Nulls::None
370                    && !self.escape_formulas,
371            },
372            names: state.names.take(),
373            len: state.len,
374            document,
375            direct: false,
376            is_map: false,
377            fields: 0,
378            record_start: 0,
379            field_ends: core::mem::take(&mut state.buffers.field_ends),
380            record: core::mem::take(&mut state.buffers.record),
381            scratch: Scratch::new(core::mem::take(&mut state.buffers.scratch)),
382            open: false,
383            limit,
384            out,
385        };
386        let had_names = writer.names.is_some();
387        let rv = drive(driver, &mut writer);
388        // the state only changes if the value was written (or a part of it,
389        // which cannot be taken back)
390        if rv.is_ok() || had_names {
391            state.names = writer.names;
392        }
393        if rv.is_ok() {
394            state.len = writer.len;
395        }
396        // the buffers are reused by the next record
397        state.buffers = Buffers {
398            field_ends: writer.field_ends,
399            record: writer.record,
400            scratch: writer.scratch.bytes,
401        };
402        rv
403    }
404}
405
406/// Builds a [`SerializerConfig`].
407///
408/// The methods have the names of the setters of [`SerializerConfig`] (without `set_`).
409#[derive(Debug, Clone)]
410#[must_use]
411pub struct SerializerConfigBuilder {
412    value: SerializerConfig,
413}
414
415impl SerializerConfigBuilder {
416    /// Creates a builder that starts with the default.
417    pub const fn new() -> SerializerConfigBuilder {
418        SerializerConfigBuilder {
419            value: SerializerConfig::new(),
420        }
421    }
422
423    /// Sets the character that separates fields (`,` by default).
424    ///
425    /// See [`SerializerConfig::set_delimiter`].
426    pub const fn delimiter(mut self, delimiter: u8) -> SerializerConfigBuilder {
427        self.value.set_delimiter(delimiter);
428        self
429    }
430
431    /// Sets the character that quotes fields (`"` by default).
432    ///
433    /// See [`SerializerConfig::set_quote`].
434    pub const fn quote(mut self, quote: Option<u8>) -> SerializerConfigBuilder {
435        self.value.set_quote(quote);
436        self
437    }
438
439    /// Sets if quotes in quoted fields are doubled (`true` by default).
440    ///
441    /// See [`SerializerConfig::set_double_quote`].
442    pub const fn double_quote(mut self, yes: bool) -> SerializerConfigBuilder {
443        self.value.set_double_quote(yes);
444        self
445    }
446
447    /// Sets how characters are escaped (not at all by default).
448    ///
449    /// See [`SerializerConfig::set_escape`].
450    pub const fn escape(mut self, escape: Escape) -> SerializerConfigBuilder {
451        self.value.set_escape(escape);
452        self
453    }
454
455    /// Sets the line ending (`\n` by default, see [`Terminator`]).
456    ///
457    /// See [`SerializerConfig::set_terminator`].
458    pub const fn terminator(mut self, terminator: Terminator) -> SerializerConfigBuilder {
459        self.value.set_terminator(terminator);
460        self
461    }
462
463    /// Sets when fields are quoted ([`QuoteStyle::Necessary`] by default).
464    ///
465    /// See [`SerializerConfig::set_quote_style`].
466    pub const fn quote_style(mut self, style: QuoteStyle) -> SerializerConfigBuilder {
467        self.value.set_quote_style(style);
468        self
469    }
470
471    /// Sets if the names of the columns are written before the first
472    ///
473    /// See [`SerializerConfig::set_headers`].
474    pub const fn headers(mut self, yes: bool) -> SerializerConfigBuilder {
475        self.value.set_headers(yes);
476        self
477    }
478
479    /// Sets the names of the columns (by default they are the keys of the
480    ///
481    /// See [`SerializerConfig::set_columns`].
482    pub const fn columns(mut self, names: &'static [&'static str]) -> SerializerConfigBuilder {
483        self.value.set_columns(names);
484        self
485    }
486
487    /// Sets how null is written ([`Nulls::None`] by default).
488    ///
489    /// See [`SerializerConfig::set_nulls`].
490    pub const fn nulls(mut self, nulls: Nulls) -> SerializerConfigBuilder {
491        self.value.set_nulls(nulls);
492        self
493    }
494
495    /// Sets if records can have a different number of fields (`false` by
496    ///
497    /// See [`SerializerConfig::set_flexible`].
498    pub const fn flexible(mut self, yes: bool) -> SerializerConfigBuilder {
499        self.value.set_flexible(yes);
500        self
501    }
502
503    /// Sets if strings that spreadsheets would run as formulas are escaped
504    ///
505    /// See [`SerializerConfig::set_escape_formulas`].
506    pub const fn escape_formulas(mut self, yes: bool) -> SerializerConfigBuilder {
507        self.value.set_escape_formulas(yes);
508        self
509    }
510
511    /// Sets the context the values are serialized in.
512    ///
513    /// See [`SerializerConfig::set_context`].
514    pub fn context(mut self, context: deser_core::Context) -> SerializerConfigBuilder {
515        self.value.set_context(context);
516        self
517    }
518
519    /// Returns the built [`SerializerConfig`].
520    pub const fn build(self) -> SerializerConfig {
521        // the value cannot be moved out of the builder in a const fn as the
522        // builder needs dropping (the context has a destructor)
523        // SAFETY: the value is read once and the builder is forgotten
524        let value = unsafe { core::ptr::read(&self.value) };
525        core::mem::forget(self);
526        value
527    }
528}
529
530impl Default for SerializerConfigBuilder {
531    fn default() -> SerializerConfigBuilder {
532        SerializerConfigBuilder::new()
533    }
534}
535
536/// Drives a driver into a record writer (see `SerializerConfig::write_with`).
537type DriveFn = fn(&mut SerializeDriver<'_>, &mut RecordWriter<'_>) -> Result<bool, Error>;
538
539/// Writes the records of a driver at once.
540fn drive_whole(
541    driver: &mut SerializeDriver<'_>,
542    writer: &mut RecordWriter<'_>,
543) -> Result<bool, Error> {
544    driver
545        .drive(|event, state| writer.event(event, state))
546        .map(|()| true)
547}
548
549/// Writes the records of a driver until the writer pauses it.
550fn drive_partial(
551    driver: &mut SerializeDriver<'_>,
552    writer: &mut RecordWriter<'_>,
553) -> Result<bool, Error> {
554    driver.drive_until(writer)
555}
556
557/// Buffers that are reused for the records of a stream.
558#[derive(Clone, Default)]
559struct Buffers {
560    field_ends: Vec<usize>,
561    record: Record,
562    scratch: Vec<u8>,
563}
564
565impl core::fmt::Debug for Buffers {
566    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
567        f.debug_struct("Buffers").finish_non_exhaustive()
568    }
569}
570
571/// The state of a stream of records that is written.
572///
573/// This holds the names of the columns after the first record was written
574/// (or the given names).
575#[derive(Debug, Clone, Default)]
576pub(crate) struct WriterState {
577    names: Option<Vec<String>>,
578    // the number of fields of the records
579    len: Option<usize>,
580    // created with the first record
581    dialect: Option<Dialect>,
582    buffers: Buffers,
583}
584
585impl WriterState {
586    /// Creates the state of a stream that continues with the given names
587    /// of the columns.
588    fn with_headers(names: Vec<String>) -> WriterState {
589        WriterState {
590            len: Some(names.len()),
591            names: Some(names),
592            dialect: None,
593            buffers: Buffers::default(),
594        }
595    }
596}
597
598/// Serializes records into delimited text.
599///
600/// Every value is a record, the names of the columns are written before
601/// the first one.
602///
603/// ```
604/// use deser_csv::Serializer;
605///
606/// #[derive(deser::Serialize)]
607/// struct Row {
608///     name: &'static str,
609///     age: u32,
610/// }
611///
612/// let mut serializer = Serializer::new();
613/// serializer.serialize(&Row { name: "jane", age: 42 }).unwrap();
614/// serializer.serialize(&Row { name: "john", age: 23 }).unwrap();
615/// assert_eq!(serializer.finish(), "name,age\njane,42\njohn,23\n");
616/// ```
617///
618/// The serializer is also the stream serializer of delimited text (see
619/// [`StreamSerializer`](ser::StreamSerializer)): the output can be taken
620/// while records are written.  To write to a [`Write`](std::io::Write) use
621/// [`SerializerConfig::writer`].  A serializer created with
622/// [`document`](Self::document) writes the records of sequences instead,
623/// like [`SerializerConfig::to_string`].
624#[derive(Debug, Clone)]
625pub struct Serializer {
626    config: SerializerConfig,
627    state: WriterState,
628    out: Vec<u8>,
629    // the values are sequences of records
630    document: bool,
631    // a document was started with `drive_partial` and is not complete
632    in_progress: bool,
633}
634
635impl Default for Serializer {
636    fn default() -> Serializer {
637        Serializer::new()
638    }
639}
640
641impl Serializer {
642    /// Creates a serializer.
643    pub fn new() -> Serializer {
644        Serializer::with_config(SerializerConfig::new())
645    }
646
647    /// Creates a serializer with the given configuration.
648    pub fn with_config(config: SerializerConfig) -> Serializer {
649        Serializer::with_state(config, WriterState::default(), false)
650    }
651
652    /// Creates a serializer for a stream that continues with the given
653    /// names of the columns.
654    ///
655    /// The names are not written, for instance because the records are
656    /// appended to an existing file.
657    ///
658    /// ```
659    /// use std::collections::BTreeMap;
660    /// use deser_csv::{Serializer, SerializerConfig};
661    ///
662    /// let mut serializer =
663    ///     Serializer::with_headers(SerializerConfig::new(), ["b", "a"]);
664    /// serializer.serialize(&BTreeMap::from([("a", 1), ("b", 2)])).unwrap();
665    /// assert_eq!(serializer.finish(), "2,1\n");
666    /// ```
667    pub fn with_headers<I, S>(config: SerializerConfig, names: I) -> Serializer
668    where
669        I: IntoIterator<Item = S>,
670        S: Into<String>,
671    {
672        let names = names.into_iter().map(Into::into).collect();
673        Serializer::with_state(config, WriterState::with_headers(names), false)
674    }
675
676    /// Creates a serializer whose values are sequences of records.
677    ///
678    /// Every value is written like with [`SerializerConfig::to_string`]:
679    /// the elements of the sequence are the records.  The records are
680    /// written while they are serialized, so large documents can be
681    /// written in parts (see
682    /// [`StreamSerializer::drive_partial`](ser::StreamSerializer::drive_partial)).
683    ///
684    /// ```
685    /// use deser_csv::{Serializer, SerializerConfig};
686    ///
687    /// let mut serializer = Serializer::document(SerializerConfig::new());
688    /// serializer.serialize(&vec![(1, "a"), (2, "b")]).unwrap();
689    /// assert_eq!(serializer.finish(), "1,a\n2,b\n");
690    /// ```
691    pub fn document(config: SerializerConfig) -> Serializer {
692        Serializer::with_state(config, WriterState::default(), true)
693    }
694
695    fn with_state(config: SerializerConfig, state: WriterState, document: bool) -> Serializer {
696        Serializer {
697            config,
698            state,
699            out: Vec::new(),
700            document,
701            in_progress: false,
702        }
703    }
704
705    /// Returns the configuration.
706    pub fn config(&self) -> &SerializerConfig {
707        &self.config
708    }
709
710    /// Returns the names of the columns.
711    ///
712    /// This is `None` until the first record was written (unless the names
713    /// were given, see [`with_headers`](Self::with_headers)).
714    pub fn headers(&self) -> Option<&[String]> {
715        self.state.names.as_deref()
716    }
717
718    /// Serializes a record (or the records of a sequence, see
719    /// [`document`](Self::document)).
720    ///
721    /// If the record fails to serialize, nothing is written.
722    pub fn serialize<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
723        ser::Serializer::serialize(self, value)
724    }
725
726    /// Serializes a record with a configured driver.
727    ///
728    /// The callback is invoked with the driver before the value is
729    /// serialized, for instance to add [`Layer`](deser_core::ser::Layer)s.
730    pub fn serialize_with<F, T: Serialize + ?Sized>(
731        &mut self,
732        value: &T,
733        setup: F,
734    ) -> Result<(), Error>
735    where
736        F: FnOnce(&mut SerializeDriver<'_>),
737    {
738        ser::Serializer::serialize_with(self, value, setup)
739    }
740
741    /// Returns the output written so far (that was not cleared).
742    pub fn as_str(&self) -> &str {
743        // SAFETY: the output is valid UTF-8, see `into_string`
744        unsafe { core::str::from_utf8_unchecked(&self.out) }
745    }
746
747    /// Returns the output.
748    pub fn finish(self) -> String {
749        into_string(self.out)
750    }
751}
752
753impl ser::Serializer for Serializer {
754    fn drive(&mut self, driver: &mut SerializeDriver<'_>) -> Result<(), Error> {
755        if !self.config.context.is_empty() {
756            driver.set_default_context(self.config.context.clone());
757        }
758        if self.in_progress {
759            return Err(Error::in_progress());
760        }
761        let len = self.out.len();
762        match self
763            .config
764            .write_whole(&mut self.state, driver, self.document, &mut self.out)
765        {
766            Ok(()) => Ok(()),
767            Err(err) => {
768                self.out.truncate(len);
769                Err(err)
770            }
771        }
772    }
773}
774
775impl ser::StreamSerializer for Serializer {
776    fn output(&self) -> &[u8] {
777        &self.out
778    }
779
780    fn clear_output(&mut self) {
781        self.out.clear();
782    }
783
784    /// Documents are written in parts (between records).
785    fn supports_partial(&self) -> bool {
786        self.document
787    }
788
789    fn drive_partial(
790        &mut self,
791        driver: &mut SerializeDriver<'_>,
792        limit: usize,
793    ) -> Result<bool, Error> {
794        if !self.config.context.is_empty() {
795            driver.set_default_context(self.config.context.clone());
796        }
797        if !self.document || (limit == usize::MAX && !self.in_progress) {
798            ser::Serializer::drive(self, driver)?;
799            return Ok(true);
800        }
801        let len = self.out.len();
802        match self
803            .config
804            .write(&mut self.state, driver, true, &mut self.out, limit)
805        {
806            Ok(done) => {
807                self.in_progress = !done;
808                Ok(done)
809            }
810            Err(err) => {
811                // the records of the parts that were taken stay written
812                // (and the stream broken, see `in_progress`)
813                self.out.truncate(len);
814                Err(err)
815            }
816        }
817    }
818
819    fn in_progress(&self) -> bool {
820        self.in_progress
821    }
822}
823
824#[cfg(feature = "io")]
825impl SerializerConfig {
826    /// Creates a writer of a stream of records (see
827    /// [`deser::io::Writer`](deser_core::io::Writer)).
828    ///
829    /// Every value is a record, the names of the columns are written before
830    /// the first one (see [`set_headers`](Self::set_headers)).  A record that fails
831    /// to serialize is not written.
832    ///
833    /// ```
834    /// use deser_csv::SerializerConfig;
835    ///
836    /// #[derive(deser::Serialize)]
837    /// struct Row {
838    ///     name: &'static str,
839    ///     age: u32,
840    /// }
841    ///
842    /// let mut writer = SerializerConfig::new().writer(Vec::new());
843    /// writer.write(&Row { name: "jane", age: 42 }).unwrap();
844    /// writer.write(&Row { name: "john", age: 23 }).unwrap();
845    /// assert_eq!(writer.into_inner(), b"name,age\njane,42\njohn,23\n");
846    /// ```
847    pub fn writer<W: std::io::Write>(&self, writer: W) -> deser_core::io::Writer<W, Serializer> {
848        deser_core::io::Writer::new(writer, Serializer::with_config(self.clone()))
849    }
850
851    /// Serializes the records of a value to a writer.
852    ///
853    /// See [`to_writer`].
854    pub fn to_writer<W: std::io::Write, T: Serialize + ?Sized>(
855        &self,
856        writer: W,
857        value: &T,
858    ) -> Result<(), Error> {
859        deser_core::io::to_writer(writer, Serializer::document(self.clone()), value)
860    }
861}
862
863/// Serializes the records of a value to a writer.
864///
865/// The records are written while they are serialized (in parts of about
866/// 8 KiB, see [`deser::io`](deser_core::io)), so the writer does not need
867/// to be buffered and the records are not held in memory.  To write one
868/// record at a time use [`SerializerConfig::writer`].
869///
870/// ```
871/// let mut out = Vec::new();
872/// deser_csv::to_writer(&mut out, &vec![(1, "a"), (2, "b")]).unwrap();
873/// assert_eq!(out, b"1,a\n2,b\n");
874/// ```
875#[cfg(feature = "io")]
876pub fn to_writer<W: std::io::Write, T: Serialize + ?Sized>(
877    writer: W,
878    value: &T,
879) -> Result<(), Error> {
880    SerializerConfig::new().to_writer(writer, value)
881}
882
883/// Converts the output into a string.
884///
885/// The output only holds text and ASCII special characters (which the
886/// dialect checks), so it's valid UTF-8.
887fn into_string(out: Vec<u8>) -> String {
888    debug_assert!(core::str::from_utf8(&out).is_ok());
889    // SAFETY: see above
890    unsafe { String::from_utf8_unchecked(out) }
891}
892
893/// Serializes the records of a value to delimited text.
894///
895/// This uses the default [`SerializerConfig`] (CSV), see there for more
896/// information.
897///
898/// ```
899/// #[derive(deser::Serialize)]
900/// struct Row {
901///     name: &'static str,
902///     tags: Vec<&'static str>,
903/// }
904///
905/// #[derive(deser::Serialize)]
906/// struct Tagged {
907///     name: &'static str,
908///     #[deser(as = deser::adapters::Separated<';'>)]
909///     tags: Vec<&'static str>,
910/// }
911///
912/// let row = Tagged { name: "a", tags: vec!["x", "y"] };
913/// assert_eq!(deser_csv::to_string(&[row]).unwrap(), "name,tags\na,x;y\n");
914///
915/// let row = Row { name: "a", tags: vec!["x", "y"] };
916/// assert!(deser_csv::to_string(&[row]).is_err());
917/// ```
918pub fn to_string<T: Serialize + ?Sized>(value: &T) -> Result<String, Error> {
919    SerializerConfig::new().to_string(value)
920}
921
922/// The fields of a record that is collected.
923#[derive(Clone, Default)]
924struct Record {
925    /// The keys (without separators).
926    keys: Vec<u8>,
927    key_ends: Vec<usize>,
928    /// The encoded fields (without separators).
929    fields: Vec<u8>,
930    field_ends: Vec<usize>,
931}
932
933impl Record {
934    fn clear(&mut self) {
935        self.keys.clear();
936        self.key_ends.clear();
937        self.fields.clear();
938        self.field_ends.clear();
939    }
940
941    fn key(&self, index: usize) -> &[u8] {
942        let start = if index == 0 {
943            0
944        } else {
945            self.key_ends[index - 1]
946        };
947        &self.keys[start..self.key_ends[index]]
948    }
949
950    fn field(&self, index: usize) -> &[u8] {
951        let start = if index == 0 {
952            0
953        } else {
954            self.field_ends[index - 1]
955        };
956        &self.fields[start..self.field_ends[index]]
957    }
958}
959
960/// Writes the events of records.
961///
962/// Fields are written directly to the output while the keys of a record
963/// match the names of the columns in their order.  Otherwise (and for the
964/// first record, which comes after the names) the fields are collected and
965/// written in the order of the names at the end of the record.
966struct RecordWriter<'a> {
967    encoder: FieldEncoder<'a>,
968    names: Option<Vec<String>>,
969    len: Option<usize>,
970    document: bool,
971    /// The fields are written to the output directly.
972    direct: bool,
973    is_map: bool,
974    /// The number of fields of the current record.
975    fields: usize,
976    /// Where the current record starts in the output.
977    record_start: usize,
978    /// Where the fields of the current record end in the output (while
979    /// writing directly).
980    field_ends: Vec<usize>,
981    /// The collected record (while not writing directly).
982    record: Record,
983    /// The text of numbers and other atoms that are not text.
984    scratch: Scratch,
985    /// A record is being written.
986    open: bool,
987    /// The driver is paused between records once the output is this long.
988    limit: usize,
989    out: &'a mut Vec<u8>,
990}
991
992impl EventSink for RecordWriter<'_> {
993    #[inline]
994    fn event(
995        &mut self,
996        event: Event<'_>,
997        _value: SerializeRef<'_>,
998        state: &mut State,
999    ) -> Result<(), Error> {
1000        RecordWriter::event(self, event, state)
1001    }
1002
1003    #[inline]
1004    fn pause(&mut self) -> bool {
1005        // the fields of a record can still move (see `collect`)
1006        !self.open && self.out.len() >= self.limit
1007    }
1008}
1009
1010impl RecordWriter<'_> {
1011    #[inline]
1012    fn event(&mut self, event: Event<'_>, state: &State) -> Result<(), Error> {
1013        // most events are the fields of records
1014        if let Event::Atom(ref atom) = event
1015            && state.depth() == usize::from(self.document) + 1
1016        {
1017            return self.atom(atom, state.is_map_key());
1018        }
1019        self.structure(event, state)
1020    }
1021
1022    /// Handles the events that are not fields.
1023    fn structure(&mut self, event: Event<'_>, state: &State) -> Result<(), Error> {
1024        // the depth of the event, without the container it starts: 0 at the
1025        // top level, 1 in a record (2 in the record of a document)
1026        let depth = match event {
1027            Event::MapStart(_) | Event::SeqStart(_) => state.depth().saturating_sub(1),
1028            _ => state.depth(),
1029        };
1030        let record_depth = usize::from(self.document);
1031        match event {
1032            Event::SeqStart(_) | Event::SeqEnd if self.document && depth == 0 => {}
1033            _ if depth < record_depth => {
1034                return Err(Error::new(
1035                    ErrorKind::UnsupportedType,
1036                    "CSV documents are sequences of records",
1037                ));
1038            }
1039            Event::MapStart(_) | Event::SeqStart(_) if depth == record_depth => {
1040                if self.names.is_none()
1041                    && let Some(columns) = self.encoder.config.columns
1042                {
1043                    let names: Vec<String> = columns.iter().map(|name| name.to_string()).collect();
1044                    if self.encoder.config.headers {
1045                        self.write_names(&names)?;
1046                    }
1047                    self.names = Some(names);
1048                }
1049                self.is_map = matches!(event, Event::MapStart(_));
1050                self.open = true;
1051                self.direct = !self.is_map || self.names.is_some();
1052                self.fields = 0;
1053                self.record_start = self.out.len();
1054                self.field_ends.clear();
1055                self.record.clear();
1056            }
1057            Event::MapEnd | Event::SeqEnd if depth == record_depth => {
1058                self.open = false;
1059                self.finish_record()?
1060            }
1061            _ if depth == record_depth => {
1062                return Err(Error::new(
1063                    ErrorKind::UnsupportedType,
1064                    "CSV records must be maps or sequences",
1065                ));
1066            }
1067            // the ends only if layers emitted maps or sequences
1068            Event::MapStart(_) | Event::SeqStart(_) | Event::MapEnd | Event::SeqEnd => {
1069                return Err(Error::new(
1070                    ErrorKind::UnsupportedType,
1071                    "CSV fields cannot hold maps or sequences",
1072                ));
1073            }
1074            Event::Atom(ref atom) => return self.atom(atom, state.is_map_key()),
1075        }
1076        Ok(())
1077    }
1078
1079    /// Handles a key or field of a record.
1080    #[inline(always)]
1081    fn atom(&mut self, atom: &Atom<'_>, is_key: bool) -> Result<(), Error> {
1082        if is_key {
1083            return self.key(atom);
1084        }
1085        let text = self.encoder.text(atom, &mut self.scratch)?;
1086        if self.direct {
1087            if self.fields > 0 {
1088                self.out.push(self.encoder.dialect.delimiter);
1089            }
1090            self.encoder.encode(text, self.out)?;
1091            self.field_ends.push(self.out.len());
1092        } else {
1093            self.encoder.encode(text, &mut self.record.fields)?;
1094            self.record.field_ends.push(self.record.fields.len());
1095        }
1096        self.fields += 1;
1097        Ok(())
1098    }
1099
1100    /// Handles the key of a field.
1101    #[inline(always)]
1102    fn key(&mut self, atom: &Atom<'_>) -> Result<(), Error> {
1103        // most keys are the names of the columns in their order
1104        if self.direct
1105            && let Atom::Str(key) = atom
1106            && let Some(names) = &self.names
1107            && let Some(name) = names.get(self.fields)
1108            && same_key(name.as_bytes(), key.as_bytes())
1109        {
1110            return Ok(());
1111        }
1112        self.other_key(atom)
1113    }
1114
1115    /// Handles a key that is not the name of the next column (see `key`).
1116    #[inline(never)]
1117    fn other_key(&mut self, atom: &Atom<'_>) -> Result<(), Error> {
1118        let key = match atom {
1119            Atom::Null | Atom::Bytes(_) => None,
1120            atom => self.encoder.text(atom, &mut self.scratch)?,
1121        };
1122        let key = key.ok_or_else(unsupported_key)?;
1123        if !self.direct {
1124            self.record.keys.extend_from_slice(key.bytes);
1125        } else {
1126            let names = self.names.as_deref().unwrap_or_default();
1127            if let Some(name) = names.get(self.fields)
1128                && same_key(name.as_bytes(), key.bytes)
1129            {
1130                return Ok(());
1131            }
1132            let key = key.bytes.to_vec();
1133            self.collect();
1134            self.record.keys.extend_from_slice(&key);
1135        }
1136        self.record.key_ends.push(self.record.keys.len());
1137        Ok(())
1138    }
1139
1140    /// Moves the fields that were written directly into the record.
1141    fn collect(&mut self) {
1142        let names = self.names.as_deref().unwrap_or_default();
1143        let mut start = self.record_start;
1144        for (index, &end) in self.field_ends.iter().enumerate() {
1145            if index > 0 {
1146                // the delimiter
1147                start += 1;
1148            }
1149            self.record.fields.extend_from_slice(&self.out[start..end]);
1150            self.record.field_ends.push(self.record.fields.len());
1151            self.record.keys.extend_from_slice(names[index].as_bytes());
1152            self.record.key_ends.push(self.record.keys.len());
1153            start = end;
1154        }
1155        self.out.truncate(self.record_start);
1156        self.direct = false;
1157    }
1158
1159    /// Ends the record.
1160    fn finish_record(&mut self) -> Result<(), Error> {
1161        let start = self.record_start;
1162        if !self.is_map {
1163            self.check_len(self.fields)?;
1164            return self.terminate(self.fields, start);
1165        }
1166
1167        if self.direct {
1168            // the fields that follow are missing, they are null
1169            let len = self.names.as_ref().map_or(0, Vec::len);
1170            for column in self.fields..len {
1171                if column > 0 {
1172                    self.out.push(self.encoder.dialect.delimiter);
1173                }
1174                self.encoder.encode(None, self.out)?;
1175            }
1176            self.check_len(len)?;
1177            return self.terminate(len, start);
1178        }
1179
1180        let count = self.record.field_ends.len();
1181        if self.names.is_none() {
1182            // the keys are UTF-8, they are strings or written by us
1183            let names: Vec<String> = (0..count)
1184                .map(|index| String::from_utf8_lossy(self.record.key(index)).into_owned())
1185                .collect();
1186            if self.encoder.config.headers {
1187                self.write_names(&names)?;
1188            }
1189            self.names = Some(names);
1190        }
1191        let len = self.names.as_ref().map_or(0, Vec::len);
1192        self.check_len(len)?;
1193        let names = self.names.as_ref().unwrap();
1194        let start = self.out.len();
1195        let mut order = vec![None; len];
1196        for index in 0..count {
1197            let key = String::from_utf8_lossy(self.record.key(index));
1198            match names.iter().position(|name| *name == key) {
1199                Some(column) if order[column].is_none() => order[column] = Some(index),
1200                Some(_) => {
1201                    return Err(Error::new(
1202                        ErrorKind::DuplicateKey,
1203                        format!("duplicate field `{}`", key),
1204                    ));
1205                }
1206                None => {
1207                    return Err(Error::new(
1208                        ErrorKind::UnknownField,
1209                        format!("field `{}` is not a column", key),
1210                    ));
1211                }
1212            }
1213        }
1214        for (column, index) in order.into_iter().enumerate() {
1215            if column > 0 {
1216                self.out.push(self.encoder.dialect.delimiter);
1217            }
1218            match index {
1219                Some(index) => self.out.extend_from_slice(self.record.field(index)),
1220                // missing fields are null
1221                None => self.encoder.encode(None, self.out)?,
1222            }
1223        }
1224        self.terminate(len, start)
1225    }
1226
1227    /// Checks the number of fields of a record.
1228    fn check_len(&mut self, len: usize) -> Result<(), Error> {
1229        match self.len {
1230            Some(expected) if expected != len && !self.encoder.config.flexible => Err(Error::new(
1231                ErrorKind::WrongLength,
1232                format!("record has {} fields, expected {}", len, expected),
1233            )),
1234            Some(_) => Ok(()),
1235            None => {
1236                self.len = Some(len);
1237                Ok(())
1238            }
1239        }
1240    }
1241
1242    /// Ends a record with `len` fields which starts at `start` in the
1243    /// output.
1244    fn terminate(&mut self, len: usize, start: usize) -> Result<(), Error> {
1245        if len == 1 && self.out.len() == start {
1246            // an empty line is a blank line, the only field is quoted
1247            match self.encoder.dialect.quote {
1248                Some(quote) => self.out.extend_from_slice(&[quote, quote]),
1249                None => {
1250                    return Err(Error::new(
1251                        ErrorKind::InvalidValue,
1252                        "a record with a single empty field needs quotes",
1253                    ));
1254                }
1255            }
1256        }
1257        match self.encoder.config.terminator {
1258            Terminator::Newline => self.out.push(b'\n'),
1259            Terminator::CrLf => self.out.extend_from_slice(b"\r\n"),
1260            Terminator::Byte(byte) => self.out.push(byte),
1261        }
1262        Ok(())
1263    }
1264
1265    /// Writes the names of the columns.
1266    fn write_names(&mut self, names: &[String]) -> Result<(), Error> {
1267        let start = self.out.len();
1268        for (index, name) in names.iter().enumerate() {
1269            if index > 0 {
1270                self.out.push(self.encoder.dialect.delimiter);
1271            }
1272            let text = Text {
1273                bytes: name.as_bytes(),
1274                numeric: false,
1275            };
1276            self.encoder.encode(Some(text), self.out)?;
1277        }
1278        self.terminate(names.len(), start)
1279    }
1280}
1281
1282/// The text of a field.
1283#[derive(Clone, Copy)]
1284struct Text<'a> {
1285    bytes: &'a [u8],
1286    numeric: bool,
1287}
1288
1289/// Encodes fields.
1290#[derive(Clone, Copy)]
1291struct FieldEncoder<'a> {
1292    config: &'a SerializerConfig,
1293    dialect: &'a Dialect,
1294    /// How bytes are written (from the state).
1295    bytes: BytesFormat,
1296    /// Text without special characters is written as it is: fields are
1297    /// only quoted if necessary, null is empty and formulas are not
1298    /// escaped.
1299    plain: bool,
1300}
1301
1302impl FieldEncoder<'_> {
1303    /// Encodes a field (`None` for null).
1304    #[inline(always)]
1305    fn encode(&self, text: Option<Text<'_>>, out: &mut Vec<u8>) -> Result<(), Error> {
1306        // most fields are written as they are
1307        if self.plain
1308            && let Some(Text { bytes, .. }) = text
1309            && !self.dialect.has_special(bytes)
1310        {
1311            push_bytes(out, bytes);
1312            return Ok(());
1313        }
1314        self.encode_special(text, out)
1315    }
1316
1317    /// Encodes a field that is not written as it is (see `encode`).
1318    #[inline(never)]
1319    fn encode_special(&self, text: Option<Text<'_>>, out: &mut Vec<u8>) -> Result<(), Error> {
1320        let config = self.config;
1321        let Some(Text { bytes, numeric }) = text else {
1322            if let Nulls::Text(null) = config.nulls {
1323                out.extend_from_slice(null.as_bytes());
1324            }
1325            return Ok(());
1326        };
1327        let reads_as_null = match config.nulls {
1328            Nulls::None => false,
1329            Nulls::Empty => bytes.is_empty(),
1330            Nulls::Text(null) => bytes == null.as_bytes(),
1331        };
1332        // formulas get a `'` in front and are quoted (as recommended by
1333        // OWASP)
1334        let formula = config.escape_formulas
1335            && !numeric
1336            && matches!(
1337                bytes.first(),
1338                Some(b'=' | b'+' | b'-' | b'@' | b'\t' | b'\r')
1339            );
1340        let has_special = self.dialect.has_special(bytes);
1341        let quote_style = match config.quote_style {
1342            QuoteStyle::Always => true,
1343            QuoteStyle::NonNumeric => !numeric,
1344            QuoteStyle::Necessary | QuoteStyle::Never => false,
1345        };
1346        if !quote_style && !has_special && !reads_as_null && !formula {
1347            out.extend_from_slice(bytes);
1348            return Ok(());
1349        }
1350
1351        let prefix: &[u8] = if formula { b"'" } else { b"" };
1352        let escape = config.escape.byte();
1353        let prefix_is_special = formula && self.dialect.is_special(b'\'');
1354        // without quotes, special characters are escaped (and so is the
1355        // first character of a text that would read as null)
1356        let quoted = quote_style
1357            || (formula && self.dialect.quote.is_some() && config.quote_style != QuoteStyle::Never)
1358            || (escape.is_none() && (has_special || prefix_is_special || reads_as_null))
1359            || (reads_as_null && bytes.is_empty());
1360        let text = prefix.iter().chain(bytes).copied();
1361
1362        if !quoted {
1363            for (index, byte) in text.enumerate() {
1364                if self.dialect.is_special(byte) || (index == 0 && reads_as_null) {
1365                    // `escape` is set, otherwise the field would be quoted
1366                    out.push(escape.unwrap_or(b'\\'));
1367                    out.push(self.escaped(byte));
1368                } else {
1369                    out.push(byte);
1370                }
1371            }
1372            return Ok(());
1373        }
1374
1375        let quote = match self.dialect.quote {
1376            Some(quote) if config.quote_style != QuoteStyle::Never => quote,
1377            _ => {
1378                return Err(Error::new(
1379                    ErrorKind::InvalidValue,
1380                    format!(
1381                        "field {:?} needs to be quoted",
1382                        String::from_utf8_lossy(bytes)
1383                    ),
1384                ));
1385            }
1386        };
1387        out.push(quote);
1388        if formula {
1389            self.push_quoted(b'\'', quote, out)?;
1390        }
1391        let mut bytes = bytes;
1392        loop {
1393            // copy the text up to the next character that is escaped
1394            let run = bytes
1395                .iter()
1396                .position(|&b| b == quote || Some(b) == escape)
1397                .unwrap_or(bytes.len());
1398            out.extend_from_slice(&bytes[..run]);
1399            let Some((&byte, rest)) = bytes[run..].split_first() else {
1400                break;
1401            };
1402            bytes = rest;
1403            self.push_quoted(byte, quote, out)?;
1404        }
1405        out.push(quote);
1406        Ok(())
1407    }
1408
1409    /// Writes a character in a quoted field, doubled or escaped if needed.
1410    fn push_quoted(&self, byte: u8, quote: u8, out: &mut Vec<u8>) -> Result<(), Error> {
1411        let escape = self.config.escape.byte();
1412        if byte == quote && self.config.double_quote {
1413            out.extend_from_slice(&[quote, quote]);
1414        } else if byte == quote || Some(byte) == escape {
1415            match escape {
1416                Some(escape) => out.extend_from_slice(&[escape, self.escaped(byte)]),
1417                None => {
1418                    return Err(Error::new(
1419                        ErrorKind::InvalidValue,
1420                        "quotes in quoted fields need to be doubled or escaped",
1421                    ));
1422                }
1423            }
1424        } else {
1425            out.push(byte);
1426        }
1427        Ok(())
1428    }
1429
1430    /// Returns what follows the escape character for a byte.
1431    fn escaped(&self, byte: u8) -> u8 {
1432        match (self.config.escape, byte) {
1433            (Escape::Backslash, b'\t') => b't',
1434            (Escape::Backslash, b'\n') => b'n',
1435            (Escape::Backslash, b'\r') => b'r',
1436            (_, byte) => byte,
1437        }
1438    }
1439
1440    /// Returns the text of an atom, `None` for null.
1441    ///
1442    /// Text that is not a string is written into `scratch`.
1443    #[inline(always)]
1444    fn text<'a>(
1445        &self,
1446        atom: &'a Atom<'_>,
1447        scratch: &'a mut Scratch,
1448    ) -> Result<Option<Text<'a>>, Error> {
1449        let (bytes, numeric) = match *atom {
1450            Atom::Str(ref value) | Atom::Lexical(ref value) => (value.as_bytes(), false),
1451            Atom::Null => return Ok(None),
1452            Atom::Bool(value) => (if value { &b"true"[..] } else { b"false" }, false),
1453            // numbers are formatted on the stack
1454            Atom::U64(value) => (scratch.int.format(value).as_bytes(), true),
1455            Atom::I64(value) => (scratch.int.format(value).as_bytes(), true),
1456            Atom::F64(value) => (scratch.float(value), true),
1457            Atom::F32(value) => (scratch.float(value), true),
1458            _ => return self.other_text(atom, &mut scratch.bytes),
1459        };
1460        Ok(Some(Text { bytes, numeric }))
1461    }
1462
1463    /// Returns the text of an atom that is not a number (see `text`).
1464    #[inline(never)]
1465    fn other_text<'a>(
1466        &self,
1467        atom: &'a Atom<'_>,
1468        scratch: &'a mut Vec<u8>,
1469    ) -> Result<Option<Text<'a>>, Error> {
1470        scratch.clear();
1471        let numeric = match *atom {
1472            Atom::Char(value) => {
1473                scratch.extend_from_slice(value.encode_utf8(&mut [0; 4]).as_bytes());
1474                false
1475            }
1476            Atom::Bytes(ref bytes) => {
1477                let format = bytes.fallback.copied().unwrap_or(self.bytes);
1478                let text = format
1479                    .encode(bytes)
1480                    .or_else(|| BytesFormat::BASE64.encode(bytes))
1481                    .unwrap_or_default();
1482                scratch.extend_from_slice(text.as_bytes());
1483                false
1484            }
1485            Atom::Ext(ref ext) => {
1486                if let Some(number) = ext.downcast_value_ref::<Number>() {
1487                    // numbers keep their text
1488                    scratch.extend_from_slice(number.as_str().as_bytes());
1489                } else if let Some(value) = ext.downcast_ref::<u128>() {
1490                    let _ = write!(ByteWriter(scratch), "{}", value);
1491                } else if let Some(value) = ext.downcast_ref::<i128>() {
1492                    let _ = write!(ByteWriter(scratch), "{}", value);
1493                } else {
1494                    return match ext.fallback() {
1495                        Atom::Ext(_) => Err(Error::new(
1496                            ErrorKind::UnsupportedType,
1497                            format!("CSV does not support {}", ext.name()),
1498                        )),
1499                        fallback => {
1500                            let mut inner = Scratch::new(Vec::new());
1501                            let numeric = match self.text(&fallback, &mut inner)? {
1502                                Some(text) => {
1503                                    let numeric = text.numeric;
1504                                    scratch.extend_from_slice(text.bytes);
1505                                    numeric
1506                                }
1507                                None => return Ok(None),
1508                            };
1509                            Ok(Some(Text {
1510                                bytes: scratch,
1511                                numeric,
1512                            }))
1513                        }
1514                    };
1515                }
1516                true
1517            }
1518            // values whose type was inferred from text are written as value
1519            Atom::Implicit(ref value) => {
1520                let mut inner = Scratch::new(Vec::new());
1521                return Ok(match self.text(&value.value().to_atom(), &mut inner)? {
1522                    Some(text) => {
1523                        let numeric = text.numeric;
1524                        scratch.extend_from_slice(text.bytes);
1525                        Some(Text {
1526                            bytes: scratch,
1527                            numeric,
1528                        })
1529                    }
1530                    None => None,
1531                });
1532            }
1533            _ => {
1534                return Err(Error::new(
1535                    ErrorKind::UnsupportedType,
1536                    format!("CSV does not support {}", atom.name()),
1537                ));
1538            }
1539        };
1540        Ok(Some(Text {
1541            bytes: scratch,
1542            numeric,
1543        }))
1544    }
1545}
1546
1547/// Formats into a byte buffer (`std::io::Write` is not in `core`).
1548struct ByteWriter<'a>(&'a mut Vec<u8>);
1549
1550impl fmt::Write for ByteWriter<'_> {
1551    fn write_str(&mut self, s: &str) -> fmt::Result {
1552        self.0.extend_from_slice(s.as_bytes());
1553        Ok(())
1554    }
1555}
1556
1557/// Holds the text of atoms that are not text (see `FieldEncoder::text`).
1558struct Scratch {
1559    /// Text that is not a number.
1560    bytes: Vec<u8>,
1561    int: itoa::Buffer,
1562    float: zmij::Buffer,
1563}
1564
1565impl Scratch {
1566    fn new(bytes: Vec<u8>) -> Scratch {
1567        Scratch {
1568            bytes,
1569            int: itoa::Buffer::new(),
1570            float: zmij::Buffer::new(),
1571        }
1572    }
1573
1574    /// Formats a float with the shortest text that reads back as the same
1575    /// value of its type (`f32` or `f64`), like the other formats.
1576    #[inline]
1577    fn float<F: zmij::Float>(&mut self, value: F) -> &[u8] {
1578        // `NaN`, `inf` and `-inf` like `Display`
1579        self.float.format(value).as_bytes()
1580    }
1581}
1582
1583/// Appends bytes to the output.
1584///
1585/// Fields are mostly short, and for them `extend_from_slice` spends more
1586/// time calling `memcpy` than copying.  Up to 32 bytes are copied with two
1587/// writes that overlap.
1588#[inline(always)]
1589fn push_bytes(out: &mut Vec<u8>, bytes: &[u8]) {
1590    let len = bytes.len();
1591    if len > 32 {
1592        out.extend_from_slice(bytes);
1593        return;
1594    }
1595    out.reserve(32);
1596    let start = out.len();
1597    // SAFETY: there is room for 32 bytes after the end of the output.  The
1598    // writes are within the first `len` of them and cover all of them, so
1599    // the output is initialized up to its new length.
1600    unsafe {
1601        let dst = out.as_mut_ptr().add(start);
1602        match len {
1603            0 => {}
1604            // the first, middle and last byte are all bytes
1605            1..=3 => {
1606                *dst = bytes[0];
1607                *dst.add(len / 2) = bytes[len / 2];
1608                *dst.add(len - 1) = bytes[len - 1];
1609            }
1610            4..=8 => {
1611                dst.cast::<u32>().write_unaligned(load_u32(bytes, 0));
1612                dst.add(len - 4)
1613                    .cast::<u32>()
1614                    .write_unaligned(load_u32(bytes, len - 4));
1615            }
1616            9..=16 => {
1617                dst.cast::<u64>().write_unaligned(load_u64(bytes, 0));
1618                dst.add(len - 8)
1619                    .cast::<u64>()
1620                    .write_unaligned(load_u64(bytes, len - 8));
1621            }
1622            _ => {
1623                dst.cast::<u128>().write_unaligned(load_u128(bytes, 0));
1624                dst.add(len - 16)
1625                    .cast::<u128>()
1626                    .write_unaligned(load_u128(bytes, len - 16));
1627            }
1628        }
1629        out.set_len(start + len);
1630    }
1631}
1632
1633/// Returns `true` if a key is the name of a column.
1634///
1635/// Keys are short, comparing them with words that overlap is faster than
1636/// calling `memcmp` for every field.
1637#[inline(always)]
1638fn same_key(name: &[u8], key: &[u8]) -> bool {
1639    let len = name.len();
1640    if len != key.len() {
1641        return false;
1642    }
1643    match len {
1644        0 => true,
1645        // the first, middle and last byte are all bytes
1646        1..=3 => {
1647            name[0] == key[0] && name[len / 2] == key[len / 2] && name[len - 1] == key[len - 1]
1648        }
1649        4..=8 => {
1650            load_u32(name, 0) == load_u32(key, 0)
1651                && load_u32(name, len - 4) == load_u32(key, len - 4)
1652        }
1653        9..=16 => {
1654            load_u64(name, 0) == load_u64(key, 0)
1655                && load_u64(name, len - 8) == load_u64(key, len - 8)
1656        }
1657        _ => name == key,
1658    }
1659}
1660
1661#[cold]
1662fn unsupported_key() -> Error {
1663    Error::new(
1664        ErrorKind::UnsupportedType,
1665        "the keys of records must be strings, numbers or booleans",
1666    )
1667}
1668
1669#[cfg(test)]
1670mod tests {
1671    use super::*;
1672
1673    #[test]
1674    fn test_push_bytes() {
1675        let text: Vec<u8> = (b'a'..=b'z').chain(b'A'..=b'Z').collect();
1676        for len in 0..=text.len() {
1677            for prefix in [0, 1, 7] {
1678                let mut out = vec![b'-'; prefix];
1679                push_bytes(&mut out, &text[..len]);
1680                assert_eq!(&out[prefix..], &text[..len]);
1681                assert_eq!(out.len(), prefix + len);
1682            }
1683        }
1684    }
1685
1686    #[test]
1687    fn test_same_key() {
1688        let text: Vec<u8> = (b'a'..=b'z').chain(b'A'..=b'Z').collect();
1689        for len in 0..=text.len() {
1690            let name = &text[..len];
1691            assert!(same_key(name, &text[..len]));
1692            if len > 0 {
1693                assert!(!same_key(name, &text[..len - 1]));
1694                assert!(!same_key(&text[..len - 1], name));
1695            }
1696            for pos in 0..len {
1697                let mut key = name.to_vec();
1698                key[pos] ^= 1;
1699                assert!(!same_key(name, &key), "{:?}", key);
1700            }
1701        }
1702    }
1703}