Skip to main content

Module vocabulary

Module vocabulary 

Expand description

Closed-vocabulary string parsing — the single spelling contract every enum a caller names by string routes through.

A vocabulary is a closed set the caller selects from by name ("straight", "one_sided", "nelson_siegel"), as opposed to an open identifier such as a currency or an ISIN. Before this module each such vocabulary was parsed by a hand-rolled match in the binding layer, so alias rules and error messages were invented per call site and Rust callers got a different vocabulary from Python callers.

impl_vocabulary! generates code() and FromStr from one variant-to-spelling mapping, so the accepted set and the error message that advertises it are derived from the same list and cannot drift.

§Normalization

The normalization is deliberately aggressive: it upper-cases and removes _, -, and whitespace, so "spread_exclusive", "spreadexclusive" and "spread-exclusive" are one spelling. That subsumes both prior conventions — core’s to_ascii_uppercase() and the binding layer’s separator rewriting — so no caller of either loses a spelling.

It is not used by the FpML code enums (DayCountFraction, and the conventions in statics::conventions): their codes are punctuated ("ACT/365.FIXED", "30E/360.ISDA") and already have hand-written parsers whose behavior is pinned by the FpML schemes.

§Listing is not normalization

That carve-out is about the normalization alone. Naming the accepted set on rejection and folding a spelling before matching are separate obligations, and a vocabulary that declines the second still owes the first: "ACT/365" must not be folded into "ACT/365.FIXED", and must still be told that "ACT/365.FIXED" is what it was one character away from.

So VocabularyParseError is deliberately reachable without impl_vocabulary!. A hand-written FromStr declares its own ACCEPTED and returns one of these, keeping its punctuated matching and gaining the message. The macro is the way to get both obligations from one list; the error type alone is the way to get listing only.

The cost of that seam is that a hand-maintained ACCEPTED can drift from the match beside it — the same duplication, moved one file closer. That is what tests/closed_vocabulary.rs exists to catch: it parses every advertised spelling of every vocabulary in the crate, hand-written ones included.

Macros§

impl_code_vocabulary 🔒
Generates ACCEPTED and FromStr for a vocabulary whose codes are punctuated by an external scheme, from one variant-to-spelling mapping.
impl_vocabulary 🔒
Generates code() and FromStr for a closed-vocabulary enum from one variant-to-spelling mapping.

Structs§

VocabularyParseError
Error parsing a closed vocabulary from a string.

Functions§

eq_code 🔒
Compares a caller’s spelling against a canonical code, folding case and nothing else — the rule for codes whose punctuation an external scheme pins.
eq_exact 🔒
Compares a caller’s spelling against a canonical code exactly, folding nothing. For a vocabulary whose case is load-bearing: "GBp" is a minor unit and "GBP" is a major currency, so folding them would silently return pence for pounds.
eq_normalized 🔒
Compares a caller’s spelling against a canonical name under normalize, without building either string.