1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
/*!
The `fixed_width` crate is designed to facilitate easy reading and writing of fixed width files.
It also provides a few useful abstractions to ease serializing and deserializing data into and out
of fixed width files.

Users of the crate will primarily use
[`Reader`](struct.Reader.html)
to read fixed width data and
[`Writer`](struct.Writer.html)
to write it.

You can read or write data as `Vec<String>` or as `Vec<Vec<u8>>`. If you use serde, then you
can also (de)serialize into and out of structs, HashMaps, etc. Since fixed width files are
not self describing, you will need to define the set of
[`Field`](struct.Field.html)
definitions for your data up front so the (de)serialization code can work.

Several errors may occur while using the library. These are defined in the
[`Error`](struct.Error.html)
type.

# Installing

Start by adding the dependency to your project in `Cargo.toml`:

```toml
fixed_width = "0.1"
```

Then in the root of your project:

```
extern crate fixed_width;
```

There is also the `fixed_width_derive` crate that provides a struct attribute syntax to ease deriving
field definitions for your types. It is optional, but if you wish to use it you can add it to your
project like so in your `Cargo.toml`:

```toml
fixed_width = "0.1"
fixed_width_derive = "0.1"
```

# Usage

Reading a `String`:

```rust
use fixed_width::Reader;
use std::result;

let mut reader = Reader::from_string("record1record2").width(7);

let records: Vec<String> = reader.string_reader()
                                 .filter_map(result::Result::ok)
                                 .collect();
```

Reading a `String` into a `Vec` of user defined structs:

```rust
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate fixed_width;

use fixed_width::{Reader, FixedWidth, Field};
use std::result;

#[derive(Deserialize)]
struct Person {
    pub name: String,
    pub age: usize,
}

impl FixedWidth for Person {
    fn fields() -> Vec<Field> {
        vec![
            Field::default().range(0..6),
            Field::default().range(6..9),
        ]
    }
}

fn main() {
    let mut reader = Reader::from_string("foobar 25barfoo 35").width(9);
    let records: Vec<Person> = reader.byte_reader()
                                     .filter_map(result::Result::ok)
                                     .map(|bytes| fixed_width::from_bytes(&bytes).unwrap())
                                     .collect();
}
```
!*/
#![crate_name = "fixed_width"]
#![deny(missing_docs)]

extern crate serde;

#[cfg(test)]
#[macro_use]
extern crate serde_derive;
#[cfg(test)]
extern crate serde_bytes;

use std::ops::Range;
use std::result;

pub use de::{
    from_bytes, from_bytes_with_fields, from_str, from_str_with_fields, DeserializeError,
    Deserializer,
};
pub use error::Error;
pub use reader::{ByteReader, Reader, StringReader};
pub use ser::{to_bytes, to_string, to_writer, to_writer_with_fields, SerializeError, Serializer};
pub use writer::{AsByteSlice, Writer};

mod de;
mod error;
mod reader;
mod ser;
mod writer;

/// Convenience type for `Result` types pertaining to this library.
pub type Result<T> = result::Result<T, error::Error>;

/// Defines fixed width field definitions for a type.
pub trait FixedWidth {
    /// Returns an order independent `Vec` of field definitions.
    fn fields() -> Vec<Field>;
}

/// Justification of a fixed width field.
#[derive(Debug, Clone, PartialEq)]
pub enum Justify {
    /// Justify the field to the left in the record.
    Left,
    /// Justify the field to the right in the record.
    Right,
}

impl From<String> for Justify {
    fn from(s: String) -> Self {
        match s.to_lowercase().trim() {
            "right" => Justify::Right,
            _ => Justify::Left,
        }
    }
}

/// Defines a field in a fixed width record. There can be 1 or more fields in a fixed width record.
#[derive(Debug, Clone)]
pub struct Field {
    /// Name of the field.
    pub name: Option<String>,
    /// Byte range of the field.
    pub range: Range<usize>,
    /// The character to use for padding the field.
    pub pad_with: char,
    /// The justification (Left or Right) of the field.
    pub justify: Justify,
}

impl Default for Field {
    fn default() -> Self {
        Self {
            name: None,
            range: 0..0,
            pad_with: ' ',
            justify: Justify::Left,
        }
    }
}

impl Field {
    /// Sets the width of this field in bytes, as specified by the range (start - end).
    ///
    /// ### Example
    ///
    /// ```rust
    /// use fixed_width::Field;
    ///
    /// let field = Field::default().range(0..5);
    ///
    /// assert_eq!(field.width(), 5);
    /// ```
    pub fn width(&self) -> usize {
        self.range.end - self.range.start
    }

    /// Sets the name of this field. Mainly used when deserializing into a HashMap to derive the keys.
    ///
    /// ### Example
    ///
    /// ```rust
    /// use fixed_width::Field;
    ///
    /// let field = Field::default().name(Some("thing"));
    ///
    /// assert_eq!(field.name, Some("thing".to_string()));
    /// ```
    pub fn name<T: Into<String>>(mut self, val: Option<T>) -> Self {
        self.name = val.map(|val| val.into());
        self
    }

    /// Sets the range in bytes of this field. The start value represents the first byte of the field,
    /// and the end represents the last byte + 1 because this is an exclusive Range.
    ///
    /// ### Example
    ///
    /// ```rust
    /// use fixed_width::Field;
    ///
    /// let field = Field::default().range(0..4);
    ///
    /// assert_eq!(field.range, 0..4);
    /// ```
    pub fn range(mut self, val: Range<usize>) -> Self {
        self.range = val;
        self
    }

    /// Sets the character to use as padding the value of this field to its byte width.
    ///
    /// ### Example
    ///
    /// ```rust
    /// use fixed_width::Field;
    ///
    /// let field = Field::default().pad_with('a');
    ///
    /// assert_eq!(field.pad_with, 'a');
    /// ```
    pub fn pad_with(mut self, val: char) -> Self {
        self.pad_with = val;
        self
    }

    /// Sets the justification to use for this field. Left will align to the left and Right to the
    /// right.
    ///
    /// ### Example
    ///
    /// ```rust
    /// use fixed_width::{Field, Justify};
    ///
    /// let field = Field::default().justify(Justify::Right);
    ///
    /// assert_eq!(field.justify, Justify::Right);
    /// ```
    pub fn justify<T: Into<Justify>>(mut self, val: T) -> Self {
        self.justify = val.into();
        self
    }
}

/// The type of line break between each record that should be inserted or skipped while reading.
#[derive(Debug, Clone, PartialEq)]
pub enum LineBreak {
    /// No linebreak
    None,
    /// Break lines with \n
    Newline,
    /// Break lines with \r\n
    CRLF,
}

impl LineBreak {
    /// The width in bytes of the given line break.
    ///
    /// ### Example
    ///
    /// ```rust
    /// use fixed_width::LineBreak;
    ///
    /// let no_linebreak = LineBreak::None;
    /// let newline_linebreak = LineBreak::Newline;
    /// let crlf_linebreak = LineBreak::CRLF;
    ///
    /// assert_eq!(no_linebreak.byte_width(), 0);
    /// assert_eq!(newline_linebreak.byte_width(), 1);
    /// assert_eq!(crlf_linebreak.byte_width(), 2);
    /// ```
    pub fn byte_width(&self) -> usize {
        match self {
            LineBreak::None => 0,
            LineBreak::Newline => 1,
            LineBreak::CRLF => 2,
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn line_break_byte_width() {
        assert_eq!(LineBreak::None.byte_width(), 0);
        assert_eq!(LineBreak::Newline.byte_width(), 1);
        assert_eq!(LineBreak::CRLF.byte_width(), 2);
    }

    #[test]
    fn field_building() {
        let field = Field::default()
            .range(0..10)
            .name(Some("foo"))
            .pad_with('a')
            .justify(Justify::Right);

        assert_eq!(field.range, 0..10);
        assert_eq!(field.name.unwrap(), "foo");
        assert_eq!(field.pad_with, 'a');
        assert_eq!(field.justify, Justify::Right);
    }

    #[test]
    fn field_width() {
        let field = Field::default().range(5..23);

        assert_eq!(field.width(), 18);
    }
}