Expand description
Cleanroom parser for the .drg drag-curve text file format (MBA-1409).
.drg is a small vendor text format used to distribute Doppler-radar-measured
drag-coefficient-vs-Mach curves for individual bullets (e.g. Lapua’s free downloads
for QuickTARGET Unlimited). This module was written from publicly observable file
structure only — line layout, field separators, and column semantics inferred by
inspecting one real vendor sample locally for grammar-pinning purposes (see the task
report for structural findings). No vendor drag-coefficient data is embedded here:
every fixture in this module’s tests is synthetic, invented content.
Shared by the CLI (main.rs) and the WASM terminal (wasm.rs); lives in the library
crate — not gated behind any feature — so it compiles for wasm32-unknown-unknown.
This module is fs-free: it parses an in-memory &str, never touches std::fs. File
I/O (reading the path the user gave --drag-table, or the WASM text-ingestion glue)
stays in the caller.
§Grammar (tolerant superset covering the vendor layout and plain two-column CSV)
- Zero or more leading non-data lines (title/header/blank/comment) are skipped until
the first line that parses as exactly two finite numbers. The first non-empty
skipped line (trimmed) is captured as
ParsedDragCurve::name; if the very first line in the file is itself a data row (headerless CSV),nameisNone. - From that point on, every non-blank line must parse as exactly two finite numbers — garbage after data has started is a hard error, not silently skipped.
- Fields are separated by a run of whitespace (space or tab — real vendor files use
tab) or by a single
,/;delimiter. - Columns may appear as
(mach, cd)or(cd, mach). Column detection: if exactly one column is strictly ascending across every row, that column is mach (this is not merely a defensive fallback — some real vendor files use(cd, mach)column order, so this detection is load-bearing). If both columns ascend — e.g. a(cd, mach)file whose cd happens to be monotonic across a subsonic-only deck — the column with the larger maximum value is mach: mach spans past1.0in real decks, while cd stays well under1.5. If the two maxima are within 20% of each other, that’s too close to call, and parsing fails with a dedicated “ambiguous columns” error rather than silently guessing. If neither column ascends, parsing fails with a dedicated error naming the problem. - The decimal separator is
.only. A line is only flagged as the decimal-comma error if it splits into exactly two tokens and both look like decimal-comma numbers (e.g."0,5 0,3"); this produces a dedicated error naming the problem, rather than a generic parse failure or a comma-CSV misread. A line where only one token looks like a decimal-comma number — e.g. a header line mixing prose and a comma-formatted number such as"Density 1,225"— is not treated as this error; it is simply skipped like ordinary header text. - Row count must be in
2..=4096(4096matchesffi::MAX_FFI_DRAG_TABLE_LEN, the cap already enforced on the array-based FFI drag-table entry point). machmust be finite and>= 0(the real vendor sample’s first row is exactlymach = 0);cdmust be finite and> 0.
Structs§
- Parsed
Drag Curve - A drag curve parsed from
.drgtext: an optional vendor-supplied name/description and the(mach, cd)points in ascending-mach order.
Functions§
- looks_
like_ drg - Cheap sniff: does
textlook like.drg(or headerless two-column CSV of the same shape)? Finds the first two data rows and checks that one of the two columns is ascending between them — a bounded scan that does not allocate the full points vector (unlike callingparse_drgand checkingis_ok()), so it’s cheap to use as a pre-check before committing to a full parse. - parse_
drg - Parses
.drgdrag-curve text into aParsedDragCurve. See the module docs for the full tolerance contract. On any violation, returnsErr(String)naming the offending line number (1-indexed) and the problem.