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}