1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! Payment scheme-specific validation.
//!
//! Each payment scheme (`FedNow`, SEPA, `CBPR+`) has additional rules beyond the
//! base ISO 20022 schema. This module provides validators that enforce these
//! scheme-specific constraints.
//!
//! # Design
//!
//! Scheme validators support two validation paths:
//!
//! 1. **XML-based** ([`SchemeValidator::validate`]) — operates on raw XML
//! strings using lightweight string scanning ([`xml_scan`]).
//! 2. **Typed** ([`SchemeValidator::validate_typed`]) — operates on
//! deserialized message structs via `std::any::Any` downcasting.
//!
//! The typed path is preferred when the caller has already deserialized the
//! message. It avoids fragile XML string scanning and catches field-level
//! issues at compile time (within the validator implementation).
//!
//! # Error Paths
//!
//! Error paths in [`ValidationError`](crate::error::ValidationError) follow
//! XPath-like conventions:
//!
//! | Style | Example | When |
//! |---|---|---|
//! | Absolute | `/Document/FIToFICstmrCdtTrf/GrpHdr/MsgId` | Typed path (field known) |
//! | Abbreviated | `//BICFI` | XML scan (element found anywhere) |
//! | Root element | `/AppHdr` | Envelope-level checks |
//!
//! **New validators should prefer absolute paths** when the field location is
//! known (always the case for typed validators). Abbreviated `//Element`
//! paths are acceptable for XML-scan checks that match elements regardless
//! of position.
//!
//! # Usage
//!
//! ```rust
//! use mx20022_validate::schemes::fednow::FedNowValidator;
//! use mx20022_validate::schemes::SchemeValidator;
//!
//! let validator = FedNowValidator::new();
//! let xml = r#"<?xml version="1.0"?><Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.13"></Document>"#;
//! let result = validator.validate(xml, "pacs.008.001.13");
//! // Result may contain errors for missing mandatory fields.
//! println!("{} error(s)", result.error_count());
//! ```
pub
use Any;
use crateValidationResult;
/// A scheme-specific validator for ISO 20022 payment messages.
///
/// Provides two validation paths: XML-based ([`validate`](SchemeValidator::validate))
/// and typed ([`validate_typed`](SchemeValidator::validate_typed)).
///
/// # Contract
///
/// - `validate` **must** return an empty [`ValidationResult`] (no errors,
/// no warnings) for message types not listed in
/// [`supported_messages`](SchemeValidator::supported_messages).
/// - `validate_typed` returns `None` for unsupported message types or
/// failed downcasts, and `Some(result)` for actual validation.
/// - Neither method should panic; callers may provide malformed XML or
/// unrecognised types.
/// - Implementations should be `Send + Sync` so they can be stored in
/// `Arc<dyn SchemeValidator>`.
/// Extract the short message type (e.g. `"pacs.008"`) from a full type
/// string like `"pacs.008.001.13"`.