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
133
134
135
136
137
138
139
140
141
142
use super::*;
impl StripeIdKind {
/// Return the wire prefix Stripe uses for this resource family.
///
/// # Returns
///
/// - `&'static str` - the two-character prefix, such as `pi` for a
/// PaymentIntent.
pub const fn prefix(&self) -> &'static str {
match self {
StripeIdKind::CheckoutSession => "cs",
StripeIdKind::Charge => "ch",
StripeIdKind::Customer => "cus",
StripeIdKind::PaymentIntent => "pi",
StripeIdKind::PaymentMethod => "pm",
StripeIdKind::Refund => "re",
StripeIdKind::Event => "evt",
}
}
/// Return the Stripe `object` name for this resource family.
///
/// # Returns
///
/// - `&'static str` - the value Stripe puts in the `object` field
/// of a response body for this family.
pub const fn object_name(&self) -> &'static str {
match self {
StripeIdKind::CheckoutSession => OBJECT_CHECKOUT_SESSION,
StripeIdKind::Charge => OBJECT_CHARGE,
StripeIdKind::Customer => OBJECT_CUSTOMER,
StripeIdKind::PaymentIntent => OBJECT_PAYMENT_INTENT,
StripeIdKind::PaymentMethod => OBJECT_PAYMENT_METHOD,
StripeIdKind::Refund => OBJECT_REFUND,
StripeIdKind::Event => OBJECT_EVENT,
}
}
/// Return whether a wire value carries this family's prefix.
///
/// A Stripe identifier always begins with its type prefix followed
/// by an underscore, so this rejects a PaymentIntent identifier
/// whose body happens to start with another family's letters.
///
/// # Arguments
///
/// - `&str` - the wire value to check.
///
/// # Returns
///
/// - `bool` - `true` when the value starts with this family's
/// prefix followed by an underscore.
pub fn matches_prefix(&self, value: &str) -> bool {
let prefix: &str = self.prefix();
value
.strip_prefix(prefix)
.is_some_and(|rest: &str| rest.starts_with('_'))
}
}
impl StripeId {
/// Build an identifier from its resource family and wire value.
///
/// This constructor trusts the caller. Use `parse` when the value
/// comes from an untyped response body and the family must be
/// derived from the prefix.
///
/// # Arguments
///
/// - `StripeIdKind` - the resource family the identifier addresses.
/// - `String` - the full wire value, normally starting with the
/// family's prefix followed by an underscore.
///
/// # Returns
///
/// - `Self` - the typed identifier.
pub const fn new(kind: StripeIdKind, raw: String) -> Self {
Self { kind, raw }
}
/// Derive the resource family from a wire value's prefix.
///
/// Stripe's family prefixes are mutually exclusive, so the first
/// family whose prefix matches wins. A value carrying no known
/// prefix is rejected rather than silently defaulting to some
/// resource, because guessing here would let a charge identifier
/// be passed to the refund endpoint.
///
/// # Arguments
///
/// - `&str` - the wire value, for example `pi_3Abc...`.
///
/// # Returns
///
/// - `Result<Self, StripeParseError>` - the typed identifier, or an
/// error when the value carries no known family prefix.
pub fn parse(raw: &str) -> Result<Self, StripeParseError> {
let families: [StripeIdKind; 7] = [
StripeIdKind::CheckoutSession,
StripeIdKind::Charge,
StripeIdKind::Customer,
StripeIdKind::PaymentIntent,
StripeIdKind::PaymentMethod,
StripeIdKind::Refund,
StripeIdKind::Event,
];
for family in families {
if family.matches_prefix(raw) {
return Ok(Self {
kind: family,
raw: String::from(raw),
});
}
}
Err(StripeParseError::UnrecognisedId(String::from(raw)))
}
/// Return whether the wire value carries this identifier's prefix.
///
/// # Returns
///
/// - `bool` - `true` when the stored value still matches its family.
pub fn has_valid_prefix(&self) -> bool {
self.get_kind().matches_prefix(self.get_raw())
}
}
impl Display for StripeId {
/// Render the full wire value.
///
/// # Arguments
///
/// - `&mut Formatter<'_>` - the formatter to write the value into.
///
/// # Returns
///
/// A `Formatter` writing the identifier's raw wire value.
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
write!(formatter, "{}", self.get_raw())
}
}