Skip to main content

Module cfi

Module cfi 

Source
Expand description

CFI (Classification of Financial Instruments) — the ISO 10962 six-letter code that classifies a financial instrument by category, group, and four attributes.

This module provides the validated Rust representation (Cfi) and the parsing, validation, and error types that surround it. It accepts the canonical 6-character form (optionally surrounded by whitespace, in any ASCII case), normalizes it, and guarantees that any constructed Cfi describes a combination actually defined by ISO 10962. There is no partially validated state: if you hold a Cfi, it is valid.

§What this type represents

A CFI has 6 characters, all uppercase letters, split into three parts:

PositionsLengthSegmentMeaning
11CategoryThe broadest class of instrument (e.g. E = equities)
21GroupA subdivision within the category (meaning depends on the category)
3–64AttributesFour attribute codes whose meaning depends on the category and group
┌────────────────────────────────────────┐
│ Cat │ Grp │  Attribute 1..4 (4 chars)  │
│  E  │  S  │   V     U     F     R      │
└────────────────────────────────────────┘

Cfi stores those 6 characters as normalized uppercase ASCII and exposes borrowed/char accessors for the category (Cfi::category), the group (Cfi::group), the four attributes (Cfi::attributes), and the whole value (Cfi::as_str).

§Validation rules — taxonomy, not checksum

Unlike Cnpj (Módulo 11) or Isin (Luhn), a CFI carries no check digit. Its validity is defined entirely by the ISO 10962 code taxonomy, which this crate embeds as a generated, no_std lookup table. Every fallible constructor runs the same rules, in order, and each maps to one CfiError variant:

  1. Length — after surrounding whitespace is trimmed, the input must contain exactly 6 characters (CfiError::InvalidLength). Cfi::parse rejects empty input up front (CfiError::Empty).
  2. Character class — every position must be an uppercase ASCII letter (CfiError::InvalidCharacter).
  3. Category — position 1 must be a category defined by ISO 10962 (CfiError::UnknownCategory).
  4. Group — position 2 must be a group defined for that category (CfiError::UnknownGroup).
  5. Attributes — each of positions 3–6 must be a code the standard permits for the resolved category and group at that attribute position (CfiError::InvalidAttribute).

Only the classification codes are embedded — not ISO’s descriptive text — so this crate can tell you a CFI is well-formed and which position is wrong, but it does not resolve the codes to their human-readable meanings.

§Design notes

  • No invalid state is representable. Cfi’s only field is private; the only ways to obtain one — Cfi::parse, Cfi::new, Cfi::from_bytes, FromStr, and TryFrom<&str> — all run full validation. There is no unchecked constructor.
  • Zero allocation, Copy, no_std-friendly. Cfi is a 6-byte value type wrapping [u8; 6]. Parsing, validating, and every accessor operate on the stack; the taxonomy lookup is a couple of binary searches and bitmask tests over a static table.
  • Ordering and hashing are byte-wise. Cfi derives Ord and Hash directly over its ASCII bytes, matching str ordering on Cfi::as_str. This is lexicographic string order, with no taxonomic meaning.
  • Safe to use as a map/set key. Cfi implements Eq and Hash consistently with PartialEq, so it works as a HashMap/HashSet or BTreeMap/BTreeSet key out of the box.

§Feature flags

This module’s optional integrations are off by default and purely additive — enabling one never changes the behavior of Cfi::parse or the validation rules above:

  • serde — (de)serializes Cfi as its 6-character string (e.g. "ESVUFR"). Deserialization re-runs full validation, so an untrusted payload can never produce an invalid Cfi.
  • schemars — implements JsonSchema for Cfi, describing it as a pattern-constrained string (^[A-Z]{6}$). The pattern is structural only; it cannot express which combinations are taxonomically valid. Implies serde.
  • arbitrary — implements Arbitrary for Cfi, generating taxonomically valid values for fuzz targets by walking the embedded table.
  • proptest — exposes reusable proptest strategies (ftracker_identifiers::cfi::proptest, when this feature is enabled) for generating valid Cfi values.

§Error handling

Every fallible constructor returns CfiError, which is Clone + PartialEq + Eq and implements core::error::Error and core::fmt::Display, so it composes with ? and with error-aggregation crates alike:

use ftracker_identifiers::{Cfi, CfiError};

match Cfi::parse("ESZUFR") {
    Ok(cfi) => println!("valid: {cfi}"),
    Err(CfiError::InvalidAttribute { index, code, .. }) => {
        println!("attribute {index} rejected: {code}");
    }
    Err(other) => println!("rejected: {other}"),
}

§Examples

use ftracker_identifiers::Cfi;

let cfi = Cfi::parse("ESVUFR").unwrap();
assert_eq!(cfi.category(), 'E');
assert_eq!(cfi.group(), 'S');
assert_eq!(cfi.attributes(), ['V', 'U', 'F', 'R']);
assert_eq!(cfi.as_str(), "ESVUFR");

Sorting and deduplicating a batch of CFIs, e.g. after importing them from a spreadsheet:

use ftracker_identifiers::Cfi;

let mut cfis: Vec<Cfi> = ["ESVUFR", "DBFTFB", "ESVUFR"]
    .into_iter()
    .map(|s| Cfi::parse(s).unwrap())
    .collect();
cfis.sort();
cfis.dedup();
assert_eq!(cfis.len(), 2);

Modules§

proptest
Reusable proptest strategies for Cfi.

Structs§

Cfi
A validated CFI (Classification of Financial Instruments, ISO 10962).

Enums§

CfiError
The set of reasons a CFI string can fail validation.