#width #fixed #fixed-width #data

macro fixed_width_derive

Derive trait for use with the fixed_width crate

9 releases (5 breaking)

0.6.0 Apr 23, 2024
0.5.1 Jun 13, 2022
0.5.0 Apr 10, 2022
0.4.2 Feb 16, 2022
0.1.0 Jul 31, 2018

#1011 in Procedural macros

MIT license

18KB
230 lines

Fixed Width   [Build Status][tests] Latest Version Documents

The fixed_width crate is designed to facilitate easy reading and writing of fixed width files with serde support.

Fixed width in this case means that each line of the file is the same number of bytes. It supports unicode, but only if the unicode fits in the designated byte size of the record. It also provides a few useful abstractions to ease serializing and deserializing data into and out of fixed width files.

Usage

Add as a dependency:

[dependencies]
fixed_width = "0.6"

# Optionally, if you are running Rust version 1.30.0 or above and want to derive fixed width field definitions:
fixed_width_derive = "0.6"

in the root of your crate:

use fixed_width;

// and if you are using fixed_width_derive:
use fixed_width_derive::FixedWidth;

Example

Read fixed width data from a &str:

use fixed_width::{FixedWidth, Reader};

let data = "1234554321";
let mut reader = Reader::from_string(data).width(5);

for record in reader.string_reader().filter_map(std::result::Result::ok) {
    // Prints "12345" and then "54321"
    println!("{}", record);
}

Read data from a &str using serde, using fixed_width_derive:

use fixed_width::{FixedWidth, Reader};
use fixed_width_derive::FixedWidth;
use serde_derive::Deserialize;

// It is not necessary to use `fixed_width_derive`, you can manually implement the `FixedWidth` trait.
#[derive(FixedWidth, Deserialize)]
struct Record {
    #[fixed_width(range = "0..5")]
    pub n: usize,
}

let data = "1234554321";

let mut reader = Reader::from_string(data).width(5);

for bytes in reader.byte_reader().filter_map(std::result::Result::ok) {
    // You must specify the type for deserialization
    let record: Record = fixed_width::from_bytes(&bytes).unwrap();

    // Prints "12345" and then "54321"
    println!("{}", record.n);
}

Read data where there are different record types in the file:

use fixed_width::{FixedWidth, Reader};
use fixed_width_derive::FixedWidth;
use serde_derive::Deserialize;

#[derive(FixedWidth, Deserialize)]
struct Record1 {
    #[fixed_width(range = "0..1")]
    pub record_type: usize,
    #[fixed_width(range = "1..5")]
    pub state: String,
}

#[derive(FixedWidth, Deserialize)]
struct Record2 {
    #[fixed_width(range = "0..1")]
    pub record_type: usize,
    #[fixed_width(range = "1..5")]
    pub name: String,
}

let data = "0OHIO1 BOB";

let mut reader = Reader::from_string(data).width(5);

while let Some(Ok(bytes)) = reader.next_record() {
    match bytes.get(0) {
        Some(b'0') => {
            let Record1 { state, .. } = fixed_width::from_bytes(bytes).unwrap();
            assert_eq!(state, "OHIO");
        }
        Some(b'1') => {
            let Record2 { name, .. } = fixed_width::from_bytes(bytes).unwrap();
            assert_eq!(name, "BOB");
        }
        Some(_) => {}
        None => {}
    }
}

Read data from a file:

use fixed_width::Reader;
use std::fs;

// from a file path on disk
let filepath = "/path/to/file.txt";
let mut reader = Reader::from_file(filepath).width(5);

// from a file handle
let file = fs::File::open(filepath);
let mut reader = Reader::from_reader(file).width(5);

License

Licensed under MIT.

Contributing

Issues and pull requests are welcome, please add tests and documentation (if necessary) for any changes you submit.

Dependencies

~250–690KB
~16K SLoC