Crate positional

Source
Expand description

This is a library to parse and write positional files

§Getting Started

You start by defining your own struct that represent a single row in the positional file

struct RowData {
    name: String,
    surname: String,
    age: i32,
}

If you have the data in memory and want to serialize the struct in a positional file you need to annotate the struct with the ToPositionalRow derive.

use positional::ToPositionalRow;

#[derive(ToPositionalRow)]
struct RowData {
    #[field(size = 10)]
    name: String,
    #[field(size = 10, filler = '-')]
    surname: String,
    #[field(size = 5, align = "right")]
    age: i32,
}
let row_data = RowData {
    name: "test".to_string(),
    surname: "test".to_string(),
    age: 20,
};
assert_eq!("test      test------   20", row_data.to_positional_row());

If you are parsing a file you can use the FromPositionalRow derive

use positional::FromPositionalRow;

#[derive(FromPositionalRow, PartialEq, Debug)]
struct RowData {
    #[field(size = 10)]
    name: String,
    #[field(size = 10, filler = '-')]
    surname: String,
    #[field(size = 5, align = "right")]
    age: i32,
}

let row_data = RowData {
    name: "test".to_string(),
    surname: "test".to_string(),
    age: 20,
};

assert_eq!(RowData::from_positional_row("test      test------   20").unwrap(), row_data);

You can use both on the same struct if that makes sense in your domain model.

We annotate the struct to be serializable to/deserializable from a positional row. We also need to annotate every field in the struct to configure the field specification.

Possible attributes are:

attribute namemandatorytypedefaultdescription
sizeyesnumberdefine the size of the field in the positional row
fillernocharwhitespacedefine what represent the empty space in the field
alignnostring"left"define the alignment of the field. It could be left or right

§Use your own types

Fields are not limited to simple types like String or i32, you can use any type as long as it implements the trait FromStr for parsing and ToString for serializing. For the ToString implementation the library will take care of fill and trim the values for the positional representation. You just need to take care of converting the value to a string.

§Files with multiple row types

It could happen that positional files contains more than one line type. In those cases normally you can tell one row from the other by looking at one particular position in the row that identifies the row type. This is useful only for parsing, serializing is basically the same. You can use an enum to represent all rows inside a file.

use positional::{FromPositionalRow, ToPositionalRow};

#[derive(FromPositionalRow, ToPositionalRow)]
enum Rows {
    #[matcher(&row[0..2] == "10")]
    Row1(Row1Data),
    #[matcher(&row[0..2] == "20")]
    Row2(Row2Data),
}

#[derive(FromPositionalRow, ToPositionalRow)]
struct Row1Data {
    #[field(size = 2)]
    row_type: String,
    #[field(size = 20)]
    name: String,
    #[field(size = 20, align = "right")]
    age: i32,
}

#[derive(FromPositionalRow, ToPositionalRow)]
struct Row2Data {
    #[field(size = 2)]
    row_type: String,
    #[field(size = 20)]
    name: String,
    #[field(size = 20, align = "right")]
    age: i32,
}

The enum should have variants with one (and only one) anonymous parameter. To tell the row you annotate the enum variants with matcher attribute and provide an expression. The expression can access the row variable, which contains the full row as a string. In the example we are matching the two starting chars from the string with a given value

§How it works

Under the hood, the library just deals with 2 traits: FromPositionalRow, and ToPositionalRow You could use those traits and just use the positional library to handle the actual parsing/creation of the positional files.

The procedural macros FromPositionalRow and ToPositionalRow just do the implementation for you, by leveraging on annotations and rust type system.

Structs§

Reader
a positional file reader
Writer
a positional file writer

Enums§

PositionalError
library error type

Traits§

FromPositionalRow
implement this trait to mark something as parsable from a row of a positional file
ToPositionalField
a trait to represent a type that could be converted to a positional field
ToPositionalRow
implement this trait to mark something as serializable into a row of a positional file

Type Aliases§

PositionalResult
a handy type to represent results with positional errors

Derive Macros§

FromPositionalRow
Add to structs to make them deserializable from positional rows
ToPositionalRow
Add to structs to make them serializable into positional rows