ftracker_identifiers/cfi/error.rs
1use core::fmt;
2
3/// The set of reasons a CFI string can fail validation.
4///
5/// Every fallible constructor of [`Cfi`](super::Cfi) returns this type. Unlike CNPJ or ISIN, a CFI
6/// carries no checksum; instead its validity is defined by the ISO 10962 code taxonomy, so beyond
7/// the structural checks there are three *taxonomic* failure modes ([`CfiError::UnknownCategory`],
8/// [`CfiError::UnknownGroup`], [`CfiError::InvalidAttribute`]). Each variant maps to a single,
9/// specific failure so callers can react programmatically rather than parsing a message.
10#[non_exhaustive]
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum CfiError {
13 /// The input was an empty string.
14 Empty,
15
16 /// After trimming surrounding whitespace, the input did not contain exactly 6 characters.
17 InvalidLength {
18 /// The number of characters found after trimming.
19 found: usize,
20 },
21
22 /// A character outside `A`–`Z` was found at a given position. Every CFI position is an
23 /// uppercase ASCII letter.
24 InvalidCharacter {
25 /// The offending character, as originally provided (before case folding).
26 character: char,
27 /// 1-indexed position within the 6 characters.
28 position: u8,
29 },
30
31 /// The category letter (position 1) is not one defined by ISO 10962.
32 UnknownCategory {
33 /// The offending category code.
34 code: char,
35 },
36
37 /// The group letter (position 2) is not defined for the otherwise-valid category.
38 UnknownGroup {
39 /// The (valid) category code the group was looked up under.
40 category: char,
41 /// The offending group code.
42 code: char,
43 },
44
45 /// An attribute letter (positions 3–6) is not permitted for the resolved category and group at
46 /// that attribute position.
47 InvalidAttribute {
48 /// The (valid) category code.
49 category: char,
50 /// The (valid) group code.
51 group: char,
52 /// Which attribute failed, 1–4 (corresponding to CFI positions 3–6).
53 index: u8,
54 /// The offending attribute code.
55 code: char,
56 },
57}
58
59impl fmt::Display for CfiError {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 match self {
62 CfiError::Empty => f.write_str("CFI input is empty"),
63 CfiError::InvalidLength { found } => {
64 write!(f, "CFI must contain exactly 6 characters, found {found}")
65 }
66 CfiError::InvalidCharacter {
67 character,
68 position,
69 } => write!(
70 f,
71 "invalid character '{character}' at position {position} of 6: expected an uppercase letter (A-Z)"
72 ),
73 CfiError::UnknownCategory { code } => {
74 write!(f, "unknown CFI category '{code}' at position 1")
75 }
76 CfiError::UnknownGroup { category, code } => write!(
77 f,
78 "unknown CFI group '{code}' at position 2 for category '{category}'"
79 ),
80 CfiError::InvalidAttribute {
81 category,
82 group,
83 index,
84 code,
85 } => write!(
86 f,
87 "invalid CFI attribute '{code}' at position {} (attribute {index}) for category '{category}' group '{group}'",
88 index + 2
89 ),
90 }
91 }
92}
93
94impl core::error::Error for CfiError {}