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