fixed_width/
lib.rs

1/*!
2The `fixed_width` crate is designed to facilitate easy reading and writing of fixed width files with
3[serde](https://serde.rs/) support.
4It also provides a few useful abstractions to ease serializing and deserializing data into and out
5of fixed width files.
6
7Users of the crate will primarily use
8[`Reader`](struct.Reader.html)
9to read fixed width data and
10[`Writer`](struct.Writer.html)
11to write it.
12
13You can read or write data as `Vec<String>` or as `Vec<Vec<u8>>`. If you use serde, then you
14can also (de)serialize into and out of structs, HashMaps, etc. Since fixed width files are
15not self describing, you will need to define the set of
16[`FieldSet`](enum.FieldSet.html)
17definitions for your data up front so the (de)serialization code can work.
18
19Several errors may occur while using the library. These are defined in the
20[`Error`](enum.Error.html)
21type.
22
23# Installing
24
25Start by adding the dependency to your project in `Cargo.toml`:
26
27```toml
28fixed_width = "0.5"
29```
30
31Then in the root of your project:
32
33```
34use fixed_width;
35```
36
37There is also the `fixed_width_derive` crate that provides a struct attribute syntax to ease deriving
38field definitions for your types. It is optional, but if you wish to use it you can add it to your
39project like so in your `Cargo.toml`:
40
41```toml
42fixed_width = "0.5"
43fixed_width_derive = "0.5"
44```
45
46# Usage
47
48Reading a `String`:
49
50```rust
51use fixed_width::Reader;
52use std::result;
53
54let mut reader = Reader::from_string("record1record2").width(7);
55
56let records: Vec<String> = reader
57    .string_reader()
58    .filter_map(result::Result::ok)
59    .collect();
60```
61
62Reading a `String` into a `Vec` of user defined structs:
63
64```rust
65use serde_derive::Deserialize;
66use serde;
67use fixed_width::{Reader, FixedWidth, FieldSet};
68use std::result;
69
70#[derive(Deserialize)]
71struct Person {
72    pub name: String,
73    pub age: usize,
74}
75
76impl FixedWidth for Person {
77    fn fields() -> FieldSet {
78        FieldSet::Seq(vec![
79            FieldSet::new_field(0..6),
80            FieldSet::new_field(6..9),
81        ])
82    }
83}
84
85let mut reader = Reader::from_string("foobar 25barfoo 35").width(9);
86let records: Vec<Person> = reader
87    .byte_reader()
88    .filter_map(result::Result::ok)
89    .map(|bytes| fixed_width::from_bytes(&bytes).unwrap())
90    .collect();
91```
92!*/
93#![crate_name = "fixed_width"]
94#![deny(missing_docs)]
95
96pub use crate::de::{
97    deserialize, from_bytes, from_bytes_with_fields, from_str, from_str_with_fields,
98    DeserializeError, Deserializer,
99};
100pub use crate::{
101    error::Error,
102    reader::{ByteReader, Reader, StringReader},
103    ser::{to_bytes, to_string, to_writer, to_writer_with_fields, SerializeError, Serializer},
104    writer::{AsByteSlice, Writer},
105};
106use std::{ops::Range, result};
107
108mod de;
109mod error;
110mod macros;
111mod reader;
112mod ser;
113mod writer;
114
115/// Convenience type for `Result` types pertaining to this library.
116pub type Result<T> = result::Result<T, error::Error>;
117
118/// Defines fixed width field definitions for a type.
119pub trait FixedWidth {
120    /// Returns field definitaions
121    fn fields() -> FieldSet;
122}
123
124/// Justification of a fixed width field.
125#[derive(Debug, Clone, Copy, PartialEq)]
126pub enum Justify {
127    /// Justify the field to the left in the record.
128    Left,
129    /// Justify the field to the right in the record.
130    Right,
131}
132
133impl<T: AsRef<str>> From<T> for Justify {
134    fn from(s: T) -> Self {
135        match s.as_ref().to_lowercase().trim() {
136            "right" => Justify::Right,
137            "left" => Justify::Left,
138            _ => panic!("Justify must be 'left' or 'right'"),
139        }
140    }
141}
142
143/// Defines a field in a fixed width record. There can be 1 or more fields in a fixed width record.
144#[derive(Debug, Clone)]
145pub struct FieldConfig {
146    /// Name of the field.
147    name: Option<String>,
148    /// Byte range of the field.
149    range: Range<usize>,
150    /// The character to use for padding the field.
151    pad_with: char,
152    /// The justification (Left or Right) of the field.
153    justify: Justify,
154}
155
156impl Default for FieldConfig {
157    fn default() -> Self {
158        Self {
159            name: None,
160            range: 0..0,
161            pad_with: ' ',
162            justify: Justify::Left,
163        }
164    }
165}
166
167impl FieldConfig {
168    ///  Create a new field.
169    ///
170    /// ```rust
171    /// use fixed_width::FieldConfig;
172    ///
173    /// let field = FieldConfig::new(0..1);
174    /// ```
175    pub fn new(range: Range<usize>) -> Self {
176        FieldConfig {
177            range,
178            ..Default::default()
179        }
180    }
181
182    fn width(&self) -> usize {
183        self.range.end - self.range.start
184    }
185}
186
187/// Field structure definition.
188#[derive(Debug, Clone)]
189pub enum FieldSet {
190    /// For single Field
191    Item(FieldConfig),
192    /// For Sequence of Fields
193    Seq(Vec<FieldSet>),
194}
195
196impl FieldSet {
197    ///  Create a new field.
198    ///
199    /// ```rust
200    /// use fixed_width::FieldSet;
201    ///
202    /// let field = FieldSet::new_field(0..1);
203    /// ```
204    pub fn new_field(range: std::ops::Range<usize>) -> Self {
205        Self::Item(FieldConfig {
206            range,
207            ..Default::default()
208        })
209    }
210
211    /// Sets the name of this field. Mainly used when deserializing into a HashMap to derive the keys.
212    /// (This method is not valid on `FieldSet::Seq` and cause panic)
213    ///
214    /// ```rust
215    /// use fixed_width::FieldSet;
216    ///
217    /// let fields = FieldSet::Seq(vec![
218    ///     FieldSet::new_field(0..1).name("foo"),
219    ///     FieldSet::Seq(vec![
220    ///         FieldSet::new_field(0..2).name("bar"), FieldSet::new_field(0..3).name("baz")
221    ///     ])
222    /// ]);
223    /// ```
224    pub fn name<T: Into<String>>(mut self, val: T) -> Self {
225        match &mut self {
226            Self::Item(conf) => {
227                conf.name = Some(val.into());
228                self
229            }
230            _ => panic!("Setting name on FieldSet::Seq is not feasible."),
231        }
232    }
233
234    /// Sets the character to use as padding the value of this field to its byte width.
235    ///
236    /// ### Example
237    ///
238    /// ```rust
239    /// use fixed_width::FieldSet;
240    ///
241    /// let field = FieldSet::new_field(0..1).pad_with('x');
242    /// let fields = FieldSet::Seq(vec![
243    ///     FieldSet::new_field(0..1),
244    ///     FieldSet::Seq(vec![FieldSet::new_field(0..2), FieldSet::new_field(0..3)]),
245    /// ])
246    /// .pad_with('x');
247    /// ```
248    pub fn pad_with(mut self, val: char) -> Self {
249        match self {
250            Self::Item(ref mut config) => {
251                config.pad_with = val;
252                self
253            }
254            Self::Seq(seq) => Self::Seq(seq.into_iter().map(|fs| fs.pad_with(val)).collect()),
255        }
256    }
257
258    /// Sets the justification to use fields. Left will align to the left and Right to the
259    /// right.
260    ///
261    /// ### Example
262    ///
263    /// ```rust
264    /// use fixed_width::{FieldSet, Justify};
265    ///
266    /// let field = FieldSet::new_field(0..1).justify(Justify::Right);
267    /// let fields = FieldSet::Seq(vec![
268    ///     FieldSet::new_field(0..1),
269    ///     FieldSet::Seq(vec![FieldSet::new_field(0..2), FieldSet::new_field(0..3)]),
270    /// ])
271    /// .justify(Justify::Right);
272    /// ```
273    pub fn justify<T: Into<Justify>>(mut self, val: T) -> Self {
274        let val = val.into();
275        match self {
276            Self::Item(ref mut config) => {
277                config.justify = val;
278                self
279            }
280            Self::Seq(seq) => Self::Seq(seq.into_iter().map(|fs| fs.justify(val)).collect()),
281        }
282    }
283
284    /// Append `FieldSet` with the given item.
285    ///
286    /// ### Example
287    /// ```rust
288    /// use fixed_width::FieldSet;
289    ///
290    /// // Suppose field defined as:
291    /// let append_fields_1 = FieldSet::new_field(0..1).append(FieldSet::new_field(1..2));
292    /// let append_fields_2 = FieldSet::new_field(0..1).append(
293    ///     FieldSet::Seq(vec![
294    ///         FieldSet::new_field(1..2),
295    ///         FieldSet::new_field(2..3),
296    ///     ])
297    /// );
298    ///
299    /// // Are identical to:
300    /// let fields_1 = FieldSet::Seq(vec![
301    ///     FieldSet::new_field(0..1),
302    ///     FieldSet::new_field(1..2),
303    /// ]);
304    /// let fields_2 = FieldSet::Seq(vec![
305    ///     FieldSet::new_field(0..1),
306    ///     FieldSet::Seq(vec![
307    ///         FieldSet::new_field(1..2),
308    ///         FieldSet::new_field(2..3),
309    ///     ]),
310    /// ]);
311    ///
312    /// # assert_eq!(
313    /// #     format!("{:?}", append_fields_1),
314    /// #     format!("{:?}", FieldSet::Seq(vec![
315    /// #         FieldSet::new_field(0..1),
316    /// #         FieldSet::new_field(1..2),
317    /// #     ]))
318    /// # );
319    /// # assert_eq!(
320    /// #     format!("{:?}", append_fields_2),
321    /// #     format!("{:?}", FieldSet::Seq(vec![
322    /// #         FieldSet::new_field(0..1),
323    /// #         FieldSet::Seq(vec![
324    /// #             FieldSet::new_field(1..2),
325    /// #             FieldSet::new_field(2..3),
326    /// #         ]),
327    /// #     ])),
328    /// # );
329    /// ```
330    pub fn append(self, item: Self) -> Self {
331        match self {
332            Self::Item(_) => Self::Seq(vec![self, item]),
333            Self::Seq(mut seq) => {
334                seq.append(&mut vec![item]);
335                Self::Seq(seq)
336            }
337        }
338    }
339
340    /// Extend `FieldSet` with the given item.
341    ///
342    /// ### Example
343    /// ```rust
344    /// use fixed_width::FieldSet;
345    ///
346    /// // Suppose field defined as:
347    /// let extend_fields_1 = FieldSet::new_field(0..1).extend(FieldSet::new_field(1..2));
348    /// let extend_fields_2 = FieldSet::new_field(0..1).extend(
349    ///     FieldSet::Seq(vec![
350    ///         FieldSet::new_field(1..2),
351    ///         FieldSet::new_field(2..3),
352    ///     ])
353    /// );
354    ///
355    /// // Are identical to:
356    /// let fields_1 = FieldSet::Seq(vec![
357    ///     FieldSet::new_field(0..1),
358    ///     FieldSet::new_field(1..2),
359    /// ]);
360    /// let fields_2 = FieldSet::Seq(vec![
361    ///     FieldSet::new_field(0..1),
362    ///     FieldSet::new_field(1..2),
363    ///     FieldSet::new_field(2..3),
364    /// ]);
365    ///
366    /// # assert_eq!(
367    /// #     format!("{:?}", extend_fields_1),
368    /// #     format!("{:?}", FieldSet::Seq(vec![
369    /// #         FieldSet::new_field(0..1),
370    /// #         FieldSet::new_field(1..2),
371    /// #     ]))
372    /// # );
373    /// # assert_eq!(
374    /// #     format!("{:?}", extend_fields_2),
375    /// #     format!("{:?}", FieldSet::Seq(vec![
376    /// #         FieldSet::new_field(0..1),
377    /// #         FieldSet::new_field(1..2),
378    /// #         FieldSet::new_field(2..3),
379    /// #     ])),
380    /// # );
381    /// ```
382    pub fn extend(self, item: Self) -> Self {
383        match self {
384            Self::Item(_) => match item {
385                Self::Item(_) => self.append(item),
386                Self::Seq(_) => Self::Seq(vec![self]).extend(item),
387            },
388            Self::Seq(mut seq) => {
389                seq.extend(item);
390                Self::Seq(seq)
391            }
392        }
393    }
394
395    /// Converts `FieldSet` into flatten `Vec<FieldConfig>`.
396    ///
397    /// ### Example
398    ///
399    /// ```rust
400    /// use fixed_width::{FieldConfig, FieldSet};
401    ///
402    /// let fields = FieldSet::Seq(vec![
403    ///     FieldSet::Seq(vec![FieldSet::new_field(0..1), FieldSet::new_field(1..2)]),
404    ///     FieldSet::new_field(2..3)
405    /// ]);
406    /// let flatten_fields = vec![
407    ///     FieldConfig::new(0..1), FieldConfig::new(1..2), FieldConfig::new(2..3)
408    /// ];
409    ///
410    /// assert_eq!(format!("{:?}", fields.flatten()), format!("{:?}", flatten_fields));
411    /// ```
412    pub fn flatten(self) -> Vec<FieldConfig> {
413        let mut flatten = vec![];
414        let mut stack = vec![vec![self]];
415
416        while !stack.is_empty() {
417            let last = stack.last_mut().unwrap();
418            if last.is_empty() {
419                stack.pop();
420            } else {
421                let field = last.drain(..1).next().unwrap();
422                match field {
423                    FieldSet::Item(conf) => flatten.push(conf),
424                    FieldSet::Seq(seq) => stack.push(seq.to_vec()),
425                }
426            }
427        }
428
429        flatten
430    }
431}
432
433impl IntoIterator for FieldSet {
434    type Item = FieldSet;
435    type IntoIter = std::vec::IntoIter<FieldSet>;
436
437    fn into_iter(self) -> Self::IntoIter {
438        match self {
439            field @ FieldSet::Item(_) => vec![field].into_iter(),
440            FieldSet::Seq(seq) => seq.into_iter(),
441        }
442    }
443}
444
445/// The type of line break between each record that should be inserted or skipped while reading.
446#[derive(Debug, Clone, PartialEq)]
447pub enum LineBreak {
448    /// No linebreak
449    None,
450    /// Break lines with \n
451    Newline,
452    /// Break lines with \r\n
453    CRLF,
454}
455
456impl LineBreak {
457    /// The width in bytes of the given line break.
458    ///
459    /// ### Example
460    ///
461    /// ```rust
462    /// use fixed_width::LineBreak;
463    ///
464    /// let no_linebreak = LineBreak::None;
465    /// let newline_linebreak = LineBreak::Newline;
466    /// let crlf_linebreak = LineBreak::CRLF;
467    ///
468    /// assert_eq!(no_linebreak.byte_width(), 0);
469    /// assert_eq!(newline_linebreak.byte_width(), 1);
470    /// assert_eq!(crlf_linebreak.byte_width(), 2);
471    /// ```
472    pub fn byte_width(&self) -> usize {
473        match self {
474            LineBreak::None => 0,
475            LineBreak::Newline => 1,
476            LineBreak::CRLF => 2,
477        }
478    }
479}
480
481#[cfg(test)]
482mod test {
483    use super::*;
484
485    #[test]
486    fn line_break_byte_width() {
487        assert_eq!(LineBreak::None.byte_width(), 0);
488        assert_eq!(LineBreak::Newline.byte_width(), 1);
489        assert_eq!(LineBreak::CRLF.byte_width(), 2);
490    }
491
492    #[test]
493    fn fieldset_name() {
494        let field = FieldSet::new_field(0..0).name("foo");
495        let field = field.flatten().pop().unwrap();
496        assert_eq!(field.name.as_ref().unwrap(), "foo");
497    }
498
499    #[test]
500    #[should_panic]
501    fn failed_on_fieldset_name() {
502        FieldSet::Seq(vec![]).name("foo");
503    }
504
505    #[test]
506    fn fieldset_pad_with() {
507        let fields = FieldSet::Seq(vec![
508            FieldSet::new_field(0..1),
509            FieldSet::Seq(vec![FieldSet::new_field(0..2), FieldSet::new_field(0..3)]),
510        ])
511        .pad_with('a');
512
513        for field in fields.flatten() {
514            assert_eq!(field.pad_with, 'a')
515        }
516    }
517
518    #[test]
519    fn fieldset_justify() {
520        let fields = FieldSet::Seq(vec![
521            FieldSet::new_field(0..1),
522            FieldSet::Seq(vec![FieldSet::new_field(0..2), FieldSet::new_field(0..3)]),
523        ])
524        .justify(Justify::Right);
525
526        for field in fields.flatten() {
527            assert_eq!(field.justify, Justify::Right)
528        }
529    }
530
531    #[test]
532    fn fieldset_justify_str() {
533        let fields = FieldSet::Seq(vec![
534            FieldSet::new_field(0..1),
535            FieldSet::Seq(vec![FieldSet::new_field(0..2), FieldSet::new_field(0..3)]),
536        ])
537        .justify("right");
538
539        for field in fields.flatten() {
540            assert_eq!(field.justify, Justify::Right)
541        }
542    }
543
544    #[test]
545    #[should_panic]
546    fn fieldset_justify_panic() {
547        let _ = FieldSet::Seq(vec![
548            FieldSet::new_field(0..1),
549            FieldSet::Seq(vec![FieldSet::new_field(0..2), FieldSet::new_field(0..3)]),
550        ])
551        .justify("foo");
552    }
553
554    #[test]
555    fn field_building() {
556        let field = FieldSet::new_field(0..10)
557            .name("foo")
558            .pad_with('a')
559            .justify(Justify::Right);
560        let field = field.flatten().pop().unwrap();
561
562        assert_eq!(field.range, 0..10);
563        assert_eq!(field.name.as_ref().unwrap(), "foo");
564        assert_eq!(field.pad_with, 'a');
565        assert_eq!(field.justify, Justify::Right);
566    }
567}