Skip to content

sachingimhan/rust8583

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

rust8583

A Rust port of the go8583 library: an ISO 8583 message packer/unpacker with JSON-driven packagers, jPOS-style class names (IFA_*, IFB_*, IFE_*, IF_*, IFMC_*, TLV …), and BER-TLV support for DE55 (EMV) workflows.

The full knowledge base — architecture, field catalog, strategies, TLV rules, cookbook recipes, glossary — lives under docs/.

Features

  • IsoMsg with jPOS-style set/get/has_field plus dotted-path subfield access (msg.set_path("48.1", "AB")).
  • BasePackager that orchestrates MTI, primary + secondary bitmap, and per-field packagers; also usable as a sub-packager for nested private containers (e.g. DE48/DE62).
  • JSON-driven configuration (new_generic_packager / …_from_reader / …_from_config) that matches jPOS XML semantics but uses JSON.
  • A PackagerRegistry you can extend at runtime with custom classes.
  • Interpreter / Prefixer / Padder strategy primitives (ASCII, BCD, EBCDIC CP037, Binary).
  • Tlv and TlvList (with fluent builder) for BER-TLV encode/decode, including long-form length and multi-byte tags. Indefinite length is explicitly unsupported.
  • Bitmap helpers supporting 64-bit and 128-bit primary/secondary layouts, plus Base1_BITMAP126 for fixed BASE I/II private bitmaps.
  • Zero runtime dependencies beyond serde + serde_json + thiserror + hex.

Install

[dependencies]
rust8583 = "0.1"

Requires Rust 2024 edition (rustc ≥ 1.90).

Quickstart — minimal 0200

use rust8583::{new_generic_packager_from_reader, IsoMsg};

fn main() -> rust8583::Result<()> {
    let cfg = r#"{
      "fields": [
        {"id": 0,  "length": 4,  "name": "MTI",    "class": "IFA_NUMERIC"},
        {"id": 1,  "length": 16, "name": "BITMAP", "class": "IFA_BITMAP"},
        {"id": 2,  "length": 19, "name": "PAN",    "class": "IFA_LLCHAR"},
        {"id": 3,  "length": 6,  "name": "PROC",   "class": "IFA_NUMERIC"},
        {"id": 4,  "length": 12, "name": "AMOUNT", "class": "IFA_AMOUNT"},
        {"id": 11, "length": 6,  "name": "STAN",   "class": "IFA_NUMERIC"}
      ]
    }"#;
    let packager = new_generic_packager_from_reader(cfg.as_bytes())?;

    let mut msg = IsoMsg::new();
    msg.set_mti("0200");
    msg.set(2, "4567890123456789");
    msg.set(3, "000000");
    msg.set(4, "1000");
    msg.set(11, "112233");

    let raw = packager.pack(&msg)?;

    let mut parsed = IsoMsg::new();
    packager.unpack(&mut parsed, &raw)?;
    assert_eq!(parsed.get_string(2), "4567890123456789");
    Ok(())
}

Sub-packager (DE48 with sub-bitmap)

The JSON config nests a packager block on the outer field. The outer class contributes the length prefix (IFA_LLLCHAR → 3-digit ASCII), the inner packager owns the sub-bitmap and subfields.

{"id": 48, "length": 999, "name": "ADDITIONAL DATA", "class": "IFA_LLLCHAR",
 "packager": {
   "fields": [
     {"id": 0,  "length": 16, "name": "SUB-BITMAP", "class": "IFA_BITMAP"},
     {"id": 1,  "length": 2,  "name": "SUB1",       "class": "IF_CHAR"},
     {"id": 22, "length": 9,  "name": "SUB22",      "class": "IF_CHAR"}
   ]
 }
}

Populate via dotted paths:

msg.set_path("48.1", "AB")?;
msg.set_path("48.22", "AAAA00000")?;

DE55 (BER-TLV) end-to-end

use rust8583::TlvList;

let mut tl = TlvList::new();
tl.append_hex(0x9F02, "000000000100")?; // Amount
tl.append_hex(0x9F26, "ABCDEF1234567890")?; // ARQC
tl.append_hex(0x82,   "3900")?;             // AIP
let de55 = tl.pack()?;

msg.set(55, de55); // packager declares DE55 as IFA_LLLTLV or IFB_LLHTLV

On unpack, DE55 comes back as FieldValue::Tlvs(Vec<Tlv>):

if let Some(rust8583::IsoValue::Field(rust8583::FieldValue::Tlvs(list))) = parsed.get(55) {
    for t in list {
        println!("0x{:X} = {}", t.tag(), t.get_string_value());
    }
}

Register a custom field class at runtime

use rust8583::{
    AsciiInterpreter, AsciiPrefixer, IsoStringFieldPackager, LeftPadder,
    PackagerRegistry,
};

PackagerRegistry::register("IFA_LNUM", |length| {
    Box::new(IsoStringFieldPackager {
        length,
        description: String::new(),
        interpreter: Box::new(AsciiInterpreter),
        prefixer: Some(Box::new(AsciiPrefixer { length: 1 })),
        padder:   Some(Box::new(LeftPadder { pad_char: '0' })),
        fixed_bcd: false,
        binary_mode: false,
    })
});

After registration, any JSON config referencing "class": "IFA_LNUM" will use it.

Project layout

rust8583/
├── Cargo.toml
├── docs/               ← full knowledge base (read these first)
├── src/
│   ├── lib.rs          public API re-exports
│   ├── error.rs        Iso8583Error + Result alias
│   ├── msg.rs          IsoMsg, IsoValue, FieldValue (dotted-path)
│   ├── packager.rs     BasePackager + SubPackager
│   ├── field_packager.rs  IsoFieldPackager trait + IsoStringFieldPackager
│   ├── field_packagers.rs constructors for every jPOS-style class
│   ├── strategies.rs   Interpreter / Prefixer / Padder
│   ├── bitmap.rs       IfaBitmap / IfbBitmap / Base1Bitmap126
│   ├── generic_packager.rs  JSON loader + PackagerRegistry
│   ├── tlv.rs          BER-TLV primitives
│   ├── tlv_list.rs     jPOS-style TlvList + builder
│   ├── tlv_field_packager.rs  IFA_LLLTLV / IFB_LLHTLV / TLV
│   ├── iso_util.rs     hex / BCD / EBCDIC / padding helpers
│   └── main.rs         demo binary
├── testdata/packagers/ sample packager configs
│   ├── minimal_packager.json
│   ├── mastercard_like.json
│   └── cup_like.json
└── tests/
    └── integration.rs  end-to-end round-trip tests

Running

cargo build              # build the library + demo binary
cargo run                # run the cookbook demo
cargo test               # unit + integration tests
cargo clippy --all-targets

Mapping from the Go library

Go Rust
ISOMsg IsoMsg
ISOField IsoValue::Field(FieldValue)
ISOComponent interface IsoValue enum
ISOPackager BasePackager + IsoFieldPackager trait
ISOFieldPackager IsoFieldPackager trait
GenericPackager new_generic_packager_* functions
PackagerRegistry PackagerRegistry (global, thread-safe)
TLV / TLVList Tlv / TlvList
ISOUtil free functions in iso_util

Status

Core ISO 8583 pack/unpack, dotted-path sub-fields, secondary-bitmap support, BER-TLV (single + list), and the full jPOS-compatible field class catalog are implemented and round-trip tested. See tests/integration.rs for worked examples.

Not yet implemented:

  • Tertiary bitmap (fields 129–192).
  • jPOS XML packager files — use the JSON config format described in docs/04-packagers.md.

License

MIT. See crate metadata.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages