Skip to content

Architecture Overview

This document describes rustledger's crate structure and data flow.

Crate Dependency Graph

                                    ┌─────────────────┐
                                    │   rustledger    │
                                    │   (CLI binary)  │
                                    └────────┬────────┘

              ┌──────────────────────────────┼──────────────────────────────┐
              │                              │                              │
              ▼                              ▼                              ▼
    ┌─────────────────┐           ┌─────────────────┐           ┌─────────────────┐
    │ rustledger-lsp  │           │ rustledger-query│           │rustledger-plugin│
    │  (LSP server)   │           │  (BQL engine)   │           │ (plugin system) │
    └────────┬────────┘           └────────┬────────┘           └────────┬────────┘
              │                              │                              │
              └──────────────────────────────┼──────────────────────────────┘


                                  ┌─────────────────┐
                                  │rustledger-loader│
                                  │ (file loading)  │
                                  └────────┬────────┘

              ┌──────────────────────────────┼──────────────────────────────┐
              │                              │                              │
              ▼                              ▼                              ▼
    ┌─────────────────┐         ┌─────────────────────┐         ┌─────────────────┐
    │rustledger-parser│         │rustledger-validate  │         │rustledger-booking│
    │ (lexer/parser)  │         │ (validation engine) │         │ (7 booking modes)│
    └────────┬────────┘         └────────┬────────────┘         └────────┬────────┘
              │                              │                              │
              └──────────────────────────────┼──────────────────────────────┘


                                  ┌─────────────────┐
                                  │ rustledger-core │
                                  │  (core types)   │
                                  └─────────────────┘


    ┌─────────────────┐           ┌───────────────────┐
    │ rustledger-wasm │           │rustledger-importer│
    │ (JS/TS bindings)│           │      (CSV)        │
    └────────┬────────┘           └───────────────────┘

              └─────────────────► rustledger-core, parser, query

Crate Descriptions

Core Layer

CratePurposeKey Types
rustledger-coreFundamental typesAmount, Position, Inventory, Decimal, Account, Currency
rustledger-parserLogos lexer + Winnow parserDirective, Transaction, Posting, ParseError

Processing Layer

CratePurposeKey Types
rustledger-loaderFile loading, includes, cachingLoader, LoadedLedger, Options
rustledger-bookingCost basis and lot matchingBookingMethod (FIFO, LIFO, HIFO, etc.)
rustledger-validateValidation rulesValidationError, 27 error codes (E0001-E0702)

Feature Layer

CratePurposeKey Types
rustledger-queryBQL query engineQuery, Executor, Table, Row
rustledger-pluginNative + Python pluginsNativePlugin, PluginRegistry
rustledger-lspLanguage Server ProtocolLSP handlers for all standard features
rustledger-importerBank statement importCsvImporter, OfxImporter

Distribution Layer

CratePurpose
rustledgerCLI binary (rledger, bean-* commands)
rustledger-wasmWebAssembly bindings for JS/TS
rustledger-ffi-wasiFFI via WASI for embedding in any language

Data Flow

Validation Pipeline

Input File


┌─────────────────────────────────────┐
│ 1. PARSE (rustledger-parser)        │
│    - Lexer tokenizes input          │
│    - Parser builds AST              │
│    - Recovers from syntax errors    │
└─────────────────────────────────────┘


┌─────────────────────────────────────┐
│ 2. LOAD (rustledger-loader)         │
│    - Process includes               │
│    - Parse options                  │
│    - Cache compiled directives      │
└─────────────────────────────────────┘


┌─────────────────────────────────────┐
│ 3. PLUGINS (rustledger-plugin)      │
│    - Run native plugins             │
│    - Run Python plugins (WASI)      │
│    - Transform directives           │
└─────────────────────────────────────┘


┌─────────────────────────────────────┐
│ 4. BOOKING (rustledger-booking)     │
│    - Interpolate missing amounts    │
│    - Match lots (FIFO/LIFO/etc)     │
│    - Compute cost basis             │
└─────────────────────────────────────┘


┌─────────────────────────────────────┐
│ 5. VALIDATE (rustledger-validate)   │
│    - Check balance assertions       │
│    - Verify account opens/closes    │
│    - Validate commodities           │
└─────────────────────────────────────┘


Output (errors or success)

Query Pipeline

BQL Query String


┌─────────────────────────────────────┐
│ 1. PARSE QUERY                      │
│    - Tokenize SQL-like syntax       │
│    - Build query AST                │
└─────────────────────────────────────┘


┌─────────────────────────────────────┐
│ 2. LOAD LEDGER                      │
│    - Full validation pipeline       │
│    - Build posting database         │
└─────────────────────────────────────┘


┌─────────────────────────────────────┐
│ 3. EXECUTE                          │
│    - Filter (WHERE)                 │
│    - Group (GROUP BY)               │
│    - Aggregate (SUM, COUNT, etc)    │
│    - Sort (ORDER BY)                │
└─────────────────────────────────────┘


Result Table

Key Design Decisions

1. Error Recovery Parser

The parser continues after syntax errors, collecting as many errors as possible in one pass. This provides a better user experience than stopping at the first error.

See: ADR-0003: Parser Design

2. Crate Separation

Each crate has a single responsibility and can be used independently:

  • Want just parsing? Use rustledger-parser
  • Want validation? Use rustledger-validate (depends on parser)
  • Want queries? Use rustledger-query

See: ADR-0001: Crate Organization

3. Error Types

Each crate defines its own error type. The CLI crate uses anyhow to unify them. Library crates use thiserror for precise error types.

See: ADR-0002: Error Handling

4. Python Plugin Sandbox

Python plugins run in a WebAssembly sandbox (CPython compiled to WASI). This provides:

  • Security: Plugins can't access filesystem or network
  • Portability: No system Python needed
  • Compatibility: Runs existing Python plugins

5. Binary Cache

Parsed ledgers are cached to disk in a binary format. Subsequent runs skip parsing if the source hasn't changed. Cache invalidation is based on file modification times.

Performance Characteristics

OperationComplexityNotes
ParsingO(n)Single pass, no backtracking
ValidationO(n)Linear scan of directives
Balance queryO(n)Aggregates all postings
Account lookupO(1)Hash map
Lot matchingO(m)m = lots in inventory

Memory usage is proportional to ledger size, typically 3-5x smaller than Python beancount due to:

  • No Python object overhead
  • Efficient string interning
  • SmallVec for small collections