finanza/card

Payment-card primitives: PAN normalisation, Luhn validation, brand detection by IIN range, masking, BIN/last-four extraction, and expiry parsing.

IIN ranges are a static snapshot of stable card-brand prefixes and lengths and are not a BIN-to-issuer database. See doc/reference/specs/iso-iec-7812-card.md for sources.

Types

Recognised card brands. Unknown is returned when no IIN range matches.

pub type Brand {
  Visa
  Mastercard
  AmericanExpress
  Discover
  Jcb
  DinersClub
  UnionPay
  Unknown
}

Constructors

  • Visa
  • Mastercard
  • AmericanExpress
  • Discover
  • Jcb
  • DinersClub
  • UnionPay
  • Unknown

Options for mask. Build with default_mask and the with_* setters.

pub opaque type MaskOptions

Errors raised by PAN operations.

pub type ValidationError {
  EmptyInput
  InvalidCharacter
  InvalidLength(length: Int)
  InvalidLuhn
  UnknownBrand
  InvalidExpiry
}

Constructors

  • EmptyInput

    Input was empty or only contained whitespace and separators.

  • InvalidCharacter

    Input contained a non-digit character after normalisation.

  • InvalidLength(length: Int)

    The PAN’s length is not valid for any recognised brand.

  • InvalidLuhn

    The PAN failed the Luhn check.

  • UnknownBrand

    The PAN’s prefix did not match any recognised brand IIN range.

  • InvalidExpiry

    Expiry parse received a malformed MM/YY or MM/YYYY value.

Values

pub fn bin(pan pan: String) -> Result(String, ValidationError)

Extract the BIN (first six digits) of a PAN.

pub fn brand_to_string(brand brand: Brand) -> String

Render a Brand as a short upper-case identifier.

pub fn default_mask() -> MaskOptions

Default MaskOptions: keep the first 4 and last 4 digits, mask the rest with *, and group output as 4-digit blocks separated by spaces.

pub fn detect_brand(pan pan: String) -> Brand

Detect the brand of a PAN by inspecting its IIN prefix and length. Returns Unknown when no rule matches.

pub fn expiry_valid(
  expiry expiry: #(Int, Int),
  today today: #(Int, Int),
) -> Bool

Test whether the expiry date (#(month, year)) is on or after today (#(month, year)). The month component of both tuples must be in 1..=12.

Tuples are used (rather than four labelled Int arguments) so that the year/month order cannot be silently swapped at the call site.

pub fn last_four(
  pan pan: String,
) -> Result(String, ValidationError)

Extract the last four digits of a PAN.

pub fn luhn_valid(digits digits: String) -> Bool

Apply the Luhn check to a digit string. The caller is responsible for passing a normalised, all-digit string (use normalize and check the format first).

pub fn mask(
  pan pan: String,
  options options: MaskOptions,
) -> Result(String, ValidationError)

Mask a PAN, preserving the configured number of leading and trailing digits and grouping the output.

Grouping is segment-aware: the kept-first block, the mask block, and the kept-last block are grouped independently. This keeps the kept regions intact on irregular-length cards (15-digit AMEX, 14-digit Diners Club) instead of letting their final digit bleed into the next group.

pub fn normalize(pan pan: String) -> String

Strip ASCII whitespace and hyphen-style separators (-, ). Does not validate that the result is digits-only.

pub fn parse_expiry(
  input input: String,
) -> Result(#(Int, Int), ValidationError)

Parse a "MM/YY" or "MM/YYYY" expiry string into a #(month, year) tuple. Years given as two digits are expanded by prefixing 20.

pub fn validate(
  pan pan: String,
) -> Result(Brand, ValidationError)

Normalise the input, verify it contains only digits, check length and Luhn, and return the detected Brand.

pub fn with_group_separator(
  options options: MaskOptions,
  separator separator: String,
) -> MaskOptions

Override the separator inserted between groups.

pub fn with_group_size(
  options options: MaskOptions,
  size size: Int,
) -> MaskOptions

Override the grouping size (set to 0 for no grouping).

pub fn with_keep_first(
  options options: MaskOptions,
  count count: Int,
) -> MaskOptions

Override the number of leading digits to preserve.

pub fn with_keep_last(
  options options: MaskOptions,
  count count: Int,
) -> MaskOptions

Override the number of trailing digits to preserve.

pub fn with_mask_char(
  options options: MaskOptions,
  char char: String,
) -> MaskOptions

Override the character used to mask hidden digits.

Search Document