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
-
EmptyInputInput was empty or only contained whitespace and separators.
-
InvalidCharacterInput contained a non-digit character after normalisation.
-
InvalidLength(length: Int)The PAN’s length is not valid for any recognised brand.
-
InvalidLuhnThe PAN failed the Luhn check.
-
UnknownBrandThe PAN’s prefix did not match any recognised brand IIN range.
-
InvalidExpiryExpiry parse received a malformed
MM/YYorMM/YYYYvalue.
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.