cnab-fixedwidth

Crates.iocnab-fixedwidth
lib.rscnab-fixedwidth
version0.1.2
created_at2025-12-09 19:08:45.619182+00
updated_at2025-12-09 19:21:20.691871+00
descriptionUm parser robusto e type-safe para arquivos CNAB 240/400 (bancários), com validação de posições e suporte a decimais implícitos.
homepagehttps://github.com/fabiocmazzo/cnabfixedwidth
repositoryhttps://github.com/fabiocmazzo/cnabfixedwidth
max_upload_size
id1976050
size22,330
Fabio Covolo Mazzo (fabiocmazzo)

documentation

https://docs.rs/cnabfixedwidth

README

CNAB Fixed Width

Crates.io Documentation License

A robust, type-safe, and declarative Rust parser for fixed-width files, specifically designed for Brazilian Banking Standards (CNAB 240/400).

Author: Fabio Covolo Mazzo (fabiomazzo@gmail.com)

🚀 Why this crate?

Parsing CNAB files is notoriously error-prone. Most libraries use 0-based indexing (Python/C style), while banking manuals use 1-based inclusive indexing. Converting between them manually is a source of bugs.

CNAB Fixed Width solves this by allowing you to copy definitions straight from the PDF manuals into your Rust structs.

Features

  • CNAB Friendly: Uses start..end positions exactly as they appear in banking documentation (1-based, inclusive).
  • Compile-Time Safety: Detects overlapping fields during compilation. If you define a field at 1..10 and another at 10..20, your code won't compile.
  • Type Safety: automatically handles Numeric (integer), Decimal (implied scaling), and Alpha (text trimming).
  • High Performance: Zero-allocation field definition (uses &'static str and macro-generated parsers).

📦 Installation

Add this to your Cargo.toml:

[dependencies]
cnab-fixed-width = "0.1.1"

⚡ Usage

use cnab_fixed_width::{FixedWidth, FixedWidthParse};

#[derive(Debug, FixedWidth)]
pub struct HeaderArquivo {
    // Defines a numeric field from position 1 to 3 (inclusive)
    #[fw(pos = "1..3", numeric)]
    pub codigo_banco: u32,

    // Defines a numeric field from 4 to 7
    #[fw(pos = "4..7", numeric)]
    pub lote_servico: u32,

    // Defines a string field. Trims whitespace automatically.
    #[fw(pos = "103..132", alpha)]
    pub nome_empresa: String,

    // Defines a decimal field.
    // "000000001234" with scale 2 becomes 12.34
    #[fw(pos = "133..144", decimal = 2)]
    pub valor_total: f64,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let line = "3410000... (rest of the 240 char line) ...";
    
    let header = HeaderArquivo::parse(line)?;
    
    println!("Banco: {}", header.codigo_banco);
    println!("Empresa: {}", header.nome_empresa);
    println!("Valor: {:.2}", header.valor_total);

    Ok(())
}

🛠️ Attributes Reference

The #[fw(...)] attribute supports the following options:

Position (pos)

Required. Defines the start and end positions (inclusive, 1-based).

  • Format: "start..end"
  • Example: pos = "1..3" captures characters 1, 2, and 3.

Data Types (Choose one)

Attribute Rust Type Description
alpha String Alphanumeric text. Trims trailing spaces.
numeric u32, i64, etc. Integer numbers. Trims padding spaces/zeros. Returns error if non-digits are found.
decimal = N f64 Numeric value with implied decimals. N is the number of decimal places.

🛡️ Error Handling

The parser is strict. It will return an error if:

  • The line is shorter than the required fields.
  • A numeric field contains letters.
  • UTF-8 decoding fails.

🚨 Compile-Time Checks

The macro validates your layout. The following code will not compile:

Commit count: 0

cargo fmt