1mod client;
17mod registry;
18pub mod sealed;
19mod server;
20
21pub use client::*;
22pub use registry::*;
23pub use server::*;
24
25pub trait SchemeId {
30 fn namespace(&self) -> &str;
32 fn scheme(&self) -> &str;
34 fn caip_family(&self) -> String {
36 format!("{}:*", self.namespace())
37 }
38 fn id(&self) -> String {
40 format!("{}-{}", self.namespace(), self.scheme())
41 }
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
46pub struct ExactScheme;
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
50pub struct UptoScheme;
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
57pub struct BatchSettlementScheme;
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
63pub struct AuthCaptureScheme;
64
65macro_rules! impl_scheme_marker {
66 ($ty:ty, $value:literal) => {
67 impl $ty {
68 pub const VALUE: &'static str = $value;
70 }
71
72 impl std::fmt::Display for $ty {
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 f.write_str(Self::VALUE)
75 }
76 }
77
78 impl AsRef<str> for $ty {
79 fn as_ref(&self) -> &str {
80 Self::VALUE
81 }
82 }
83
84 impl std::str::FromStr for $ty {
85 type Err = String;
86 fn from_str(s: &str) -> Result<Self, Self::Err> {
87 if s == Self::VALUE {
88 Ok(Self)
89 } else {
90 Err(format!("expected '{}', got '{s}'", Self::VALUE))
91 }
92 }
93 }
94
95 impl serde::Serialize for $ty {
96 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
97 serializer.serialize_str(Self::VALUE)
98 }
99 }
100
101 impl<'de> serde::Deserialize<'de> for $ty {
102 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
103 let s = <std::borrow::Cow<'de, str>>::deserialize(deserializer)?;
107 let s = s.as_ref();
108 if s == Self::VALUE {
109 Ok(Self)
110 } else {
111 Err(serde::de::Error::custom(format!(
112 "expected '{}', got '{s}'",
113 Self::VALUE
114 )))
115 }
116 }
117 }
118 };
119}
120
121impl_scheme_marker!(ExactScheme, "exact");
122impl_scheme_marker!(UptoScheme, "upto");
123impl_scheme_marker!(BatchSettlementScheme, "batch-settlement");
124impl_scheme_marker!(AuthCaptureScheme, "auth-capture");
125
126#[cfg(test)]
127mod marker_tests {
128 use super::*;
129
130 #[test]
131 fn exact_serde_roundtrip() {
132 let encoded = serde_json::to_string(&ExactScheme).unwrap();
133 assert_eq!(encoded, r#""exact""#);
134 let decoded: ExactScheme = serde_json::from_str(&encoded).unwrap();
135 assert_eq!(decoded, ExactScheme);
136 }
137
138 #[test]
139 fn upto_serde_roundtrip() {
140 let encoded = serde_json::to_string(&UptoScheme).unwrap();
141 assert_eq!(encoded, r#""upto""#);
142 let decoded: UptoScheme = serde_json::from_str(&encoded).unwrap();
143 assert_eq!(decoded, UptoScheme);
144 }
145
146 #[test]
147 fn batch_settlement_serde_roundtrip() {
148 let encoded = serde_json::to_string(&BatchSettlementScheme).unwrap();
149 assert_eq!(encoded, r#""batch-settlement""#);
150 let decoded: BatchSettlementScheme = serde_json::from_str(&encoded).unwrap();
151 assert_eq!(decoded, BatchSettlementScheme);
152 }
153
154 #[test]
155 fn auth_capture_serde_roundtrip() {
156 let encoded = serde_json::to_string(&AuthCaptureScheme).unwrap();
157 assert_eq!(encoded, r#""auth-capture""#);
158 let decoded: AuthCaptureScheme = serde_json::from_str(&encoded).unwrap();
159 assert_eq!(decoded, AuthCaptureScheme);
160 }
161
162 #[test]
163 fn wrong_scheme_rejected() {
164 assert!(serde_json::from_str::<ExactScheme>(r#""upto""#).is_err());
165 assert!(serde_json::from_str::<UptoScheme>(r#""exact""#).is_err());
166 assert!(serde_json::from_str::<BatchSettlementScheme>(r#""exact""#).is_err());
167 assert!(serde_json::from_str::<AuthCaptureScheme>(r#""batch-settlement""#).is_err());
168 }
169
170 #[test]
175 fn markers_decode_from_owned_value() {
176 let exact: ExactScheme = serde_json::from_value(serde_json::json!("exact")).unwrap();
177 assert_eq!(exact, ExactScheme);
178 let upto: UptoScheme = serde_json::from_value(serde_json::json!("upto")).unwrap();
179 assert_eq!(upto, UptoScheme);
180 let batch: BatchSettlementScheme =
181 serde_json::from_value(serde_json::json!("batch-settlement")).unwrap();
182 assert_eq!(batch, BatchSettlementScheme);
183 let auth: AuthCaptureScheme =
184 serde_json::from_value(serde_json::json!("auth-capture")).unwrap();
185 assert_eq!(auth, AuthCaptureScheme);
186 assert!(serde_json::from_value::<ExactScheme>(serde_json::json!("upto")).is_err());
187 }
188}