a2l-parse
ASAP2/A2L ECU description parser — PROJECT/MODULE/CHARACTERISTIC/ MEASUREMENT/RECORD_LAYOUT/COMPU_METHOD, calibration data model.
Layer: L1 — substrate · Estate deps: zero · Runtime deps:
none · no_std + alloc (CI exercises thumbv7em-none-eabihf).
What's here
| Module | Contents |
|---|---|
model |
A2lProject::parse — the parsed database (project, modules); A2lModule with characteristic_by_name / measurement_by_name (plus record-layout and compu-method lookups); Characteristic (r#type: Value/Curve/Map/ValBlk/Ascii, address, deposit, max_diff, conversion, limits); Measurement (datatype, ECU_ADDRESS, conversion); RecordLayout (FNC_VALUES position + datatype); CompuMethod (LINEAR/RAT_FUNC/TABLE/IDENTITY, COEFFS/COEFFS_LINEAR/COMPU_TAB_REF, unit) with to_linear() — the raw→physical reduction every calibration consumer wants |
lexer |
Hand-rolled scanner: identifiers, /begin-style keywords, decimal/hex/float literals, quoted strings with C-style escapes (multi-byte UTF-8 safe), /* */ and // comments — get()-only byte access, total by construction |
parser |
Keyword-driven, block-structured recursive descent: consumes the required positionals of the six core blocks, captures the optional keywords the model needs, and skips everything else — unknown optional keywords, unknown /begin … /end sub-blocks (AXIS_DESCR, IF_DATA braces, vendor extensions) |
error |
A2lError — typed, exhaustive, with 1-based line numbers |
Guarantees
- Never panics: every byte access is
get()-based (deny-levelunwrap/expect/panic/indexing_slicinglints on the lib target); multi-byte UTF-8 inside strings is boundary-safe (property of the scanner, regression-tested and fuzz-found). - Skip-tolerant: real-world files with vendor blocks (
IF_DATA,AXIS_DESCR,FUNCTION,GROUP,COMPU_VTAB, OEM extensions) parse as long as the core blocks are intact. Positional runs are strict and produce typed errors. - Bounded:
/beginnesting deeper thanMAX_DEPTHis a typed error, never a stack overflow. - Compu-method math:
to_linear()reducesRAT_FUNConly when the conversion is genuinely linear (d = e = a = 0,f ≠ 0— slope from the x-coefficient), appliesCOEFFS_LINEARdirectly, and treatsIDENTITYasf(x) = x; TABLE and irreducibly-rational methods returnNonerather than a wrong approximation.
Example
use ;
let project = parse.unwrap;
let module = project.module_by_name.unwrap;
let kfile = module.characteristic_by_name.unwrap;
assert_eq!;
assert_eq!;
let meas = module.measurement_by_name.unwrap;
assert_eq!;
assert_eq!;
// Raw → physical: (0·x² + 0.00390625·x + 0) / 1.
let lin = module.compu_method_by_name.unwrap.to_linear.unwrap;
assert_eq!;
Tests
cargo test runs unit + integration suites, doctests, and a 5-property
500-case proptest battery (u32 address round-trips through
CHARACTERISTIC and MEASUREMENT in hex/decimal, datatype round-trips,
multi-characteristic ordering, coefficient reduction). cargo fuzz run a2l_parse covers the parser (it caught and fixed a UTF-8 boundary bug
before release); miri runs the lib suite; thumbv7em-none-eabihf is
checked in CI.
License
MIT OR Apache-2.0 — see LICENSE-MIT and LICENSE-APACHE.