10 releases
0.4.3 | Oct 2, 2024 |
---|---|
0.4.2 | Aug 22, 2024 |
0.4.1 | Jan 27, 2023 |
0.4.1-rc.0 | Dec 18, 2023 |
0.1.1 | May 24, 2022 |
#162 in Procedural macros
611 downloads per month
16KB
204 lines
positional.rs
This is a library for authoring and parsing positional files
lib.rs
:
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 name | mandatory | type | default | description |
---|---|---|---|---|
size | yes | number | --- | define the size of the field in the positional row |
filler | no | char | whitespace |
define what represent the empty space in the field |
align | no | string | "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.
Dependencies
~3–10MB
~106K SLoC