1use std::{collections::HashSet, fmt, str::FromStr};
2
3use serde::{Deserialize, Serialize, Serializer};
4use strum::{AsRefStr, EnumIter, IntoStaticStr, ParseError, VariantArray, VariantNames};
5
6#[derive(Debug, Default, Clone, Eq, PartialEq)]
17pub enum RpcModuleSelection {
18 All,
20 #[default]
22 Standard,
23 Selection(HashSet<RethRpcModule>),
25}
26
27impl RpcModuleSelection {
30 pub const STANDARD_MODULES: [RethRpcModule; 3] =
32 [RethRpcModule::Eth, RethRpcModule::Net, RethRpcModule::Web3];
33
34 pub fn all_modules() -> HashSet<RethRpcModule> {
36 RethRpcModule::modules().into_iter().collect()
37 }
38
39 pub fn standard_modules() -> HashSet<RethRpcModule> {
41 HashSet::from(Self::STANDARD_MODULES)
42 }
43
44 pub fn default_ipc_modules() -> HashSet<RethRpcModule> {
48 Self::all_modules()
49 }
50
51 pub fn try_from_selection<I, T>(selection: I) -> Result<Self, T::Error>
77 where
78 I: IntoIterator<Item = T>,
79 T: TryInto<RethRpcModule>,
80 {
81 selection.into_iter().map(TryInto::try_into).collect()
82 }
83
84 pub fn len(&self) -> usize {
86 match self {
87 Self::All => RethRpcModule::variant_count(),
88 Self::Standard => Self::STANDARD_MODULES.len(),
89 Self::Selection(s) => s.len(),
90 }
91 }
92
93 pub fn is_empty(&self) -> bool {
95 match self {
96 Self::Selection(sel) => sel.is_empty(),
97 _ => false,
98 }
99 }
100
101 pub fn iter_selection(&self) -> Box<dyn Iterator<Item = RethRpcModule> + '_> {
103 match self {
104 Self::All => Box::new(RethRpcModule::modules().into_iter()),
105 Self::Standard => Box::new(Self::STANDARD_MODULES.iter().copied()),
106 Self::Selection(s) => Box::new(s.iter().copied()),
107 }
108 }
109
110 pub fn to_selection(&self) -> HashSet<RethRpcModule> {
112 match self {
113 Self::All => Self::all_modules(),
114 Self::Standard => Self::standard_modules(),
115 Self::Selection(s) => s.clone(),
116 }
117 }
118
119 pub fn into_selection(self) -> HashSet<RethRpcModule> {
121 match self {
122 Self::All => Self::all_modules(),
123 Self::Standard => Self::standard_modules(),
124 Self::Selection(s) => s,
125 }
126 }
127
128 pub fn are_identical(http: Option<&Self>, ws: Option<&Self>) -> bool {
130 match (http, ws) {
131 (Some(Self::All), Some(other)) | (Some(other), Some(Self::All)) => {
133 other.len() == RethRpcModule::variant_count()
134 }
135
136 (Some(some), None) | (None, Some(some)) => some.is_empty(),
138
139 (Some(http), Some(ws)) => http.to_selection() == ws.to_selection(),
140 (None, None) => true,
141 }
142 }
143
144 pub fn contains(&self, module: &RethRpcModule) -> bool {
146 match self {
147 Self::All => true,
148 Self::Standard => Self::STANDARD_MODULES.contains(module),
149 Self::Selection(s) => s.contains(module),
150 }
151 }
152}
153
154impl From<&HashSet<RethRpcModule>> for RpcModuleSelection {
155 fn from(s: &HashSet<RethRpcModule>) -> Self {
156 Self::from(s.clone())
157 }
158}
159
160impl From<HashSet<RethRpcModule>> for RpcModuleSelection {
161 fn from(s: HashSet<RethRpcModule>) -> Self {
162 Self::Selection(s)
163 }
164}
165
166impl From<&[RethRpcModule]> for RpcModuleSelection {
167 fn from(s: &[RethRpcModule]) -> Self {
168 Self::Selection(s.iter().copied().collect())
169 }
170}
171
172impl From<Vec<RethRpcModule>> for RpcModuleSelection {
173 fn from(s: Vec<RethRpcModule>) -> Self {
174 Self::Selection(s.into_iter().collect())
175 }
176}
177
178impl<const N: usize> From<[RethRpcModule; N]> for RpcModuleSelection {
179 fn from(s: [RethRpcModule; N]) -> Self {
180 Self::Selection(s.iter().copied().collect())
181 }
182}
183
184impl<'a> FromIterator<&'a RethRpcModule> for RpcModuleSelection {
185 fn from_iter<I>(iter: I) -> Self
186 where
187 I: IntoIterator<Item = &'a RethRpcModule>,
188 {
189 iter.into_iter().copied().collect()
190 }
191}
192
193impl FromIterator<RethRpcModule> for RpcModuleSelection {
194 fn from_iter<I>(iter: I) -> Self
195 where
196 I: IntoIterator<Item = RethRpcModule>,
197 {
198 Self::Selection(iter.into_iter().collect())
199 }
200}
201
202impl FromStr for RpcModuleSelection {
203 type Err = ParseError;
204
205 fn from_str(s: &str) -> Result<Self, Self::Err> {
206 if s.is_empty() {
207 return Ok(Self::Selection(Default::default()))
208 }
209 let mut modules = s.split(',').map(str::trim).peekable();
210 let first = modules.peek().copied().ok_or(ParseError::VariantNotFound)?;
211 match first.to_lowercase().as_str() {
215 "all" => Ok(Self::All),
216 "none" => Ok(Self::Selection(Default::default())),
217 _ => Self::try_from_selection(modules),
218 }
219 }
220}
221
222impl fmt::Display for RpcModuleSelection {
223 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
224 write!(
225 f,
226 "[{}]",
227 self.iter_selection().map(|s| s.to_string()).collect::<Vec<_>>().join(", ")
228 )
229 }
230}
231
232#[derive(
234 Debug,
235 Clone,
236 Copy,
237 Eq,
238 PartialEq,
239 Hash,
240 AsRefStr,
241 IntoStaticStr,
242 VariantNames,
243 VariantArray,
244 EnumIter,
245 Deserialize,
246)]
247#[serde(rename_all = "snake_case")]
248#[strum(serialize_all = "kebab-case")]
249pub enum RethRpcModule {
250 Admin,
252 Debug,
254 Eth,
256 Net,
258 Trace,
260 Txpool,
262 Web3,
264 Rpc,
266 Reth,
268 Ots,
270 Flashbots,
272 Miner,
274 Mev,
276}
277
278impl RethRpcModule {
281 pub const fn variant_count() -> usize {
283 <Self as VariantArray>::VARIANTS.len()
284 }
285
286 pub const fn all_variant_names() -> &'static [&'static str] {
288 <Self as VariantNames>::VARIANTS
289 }
290
291 pub const fn all_variants() -> &'static [Self] {
293 <Self as VariantArray>::VARIANTS
294 }
295
296 pub fn modules() -> impl IntoIterator<Item = Self> {
298 use strum::IntoEnumIterator;
299 Self::iter()
300 }
301
302 #[inline]
304 pub fn as_str(&self) -> &'static str {
305 self.into()
306 }
307}
308
309impl FromStr for RethRpcModule {
310 type Err = ParseError;
311
312 fn from_str(s: &str) -> Result<Self, Self::Err> {
313 Ok(match s {
314 "admin" => Self::Admin,
315 "debug" => Self::Debug,
316 "eth" => Self::Eth,
317 "net" => Self::Net,
318 "trace" => Self::Trace,
319 "txpool" => Self::Txpool,
320 "web3" => Self::Web3,
321 "rpc" => Self::Rpc,
322 "reth" => Self::Reth,
323 "ots" => Self::Ots,
324 "flashbots" => Self::Flashbots,
325 "miner" => Self::Miner,
326 "mev" => Self::Mev,
327 _ => return Err(ParseError::VariantNotFound),
328 })
329 }
330}
331
332impl TryFrom<&str> for RethRpcModule {
333 type Error = ParseError;
334 fn try_from(s: &str) -> Result<Self, <Self as TryFrom<&str>>::Error> {
335 FromStr::from_str(s)
336 }
337}
338
339impl fmt::Display for RethRpcModule {
340 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
341 f.pad(self.as_ref())
342 }
343}
344
345impl Serialize for RethRpcModule {
346 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
347 where
348 S: Serializer,
349 {
350 s.serialize_str(self.as_ref())
351 }
352}
353
354#[cfg(test)]
355mod test {
356 use super::*;
357
358 #[test]
359 fn test_all_modules() {
360 let all_modules = RpcModuleSelection::all_modules();
361 assert_eq!(all_modules.len(), RethRpcModule::variant_count());
362 }
363
364 #[test]
365 fn test_standard_modules() {
366 let standard_modules = RpcModuleSelection::standard_modules();
367 let expected_modules: HashSet<RethRpcModule> =
368 HashSet::from([RethRpcModule::Eth, RethRpcModule::Net, RethRpcModule::Web3]);
369 assert_eq!(standard_modules, expected_modules);
370 }
371
372 #[test]
373 fn test_default_ipc_modules() {
374 let default_ipc_modules = RpcModuleSelection::default_ipc_modules();
375 assert_eq!(default_ipc_modules, RpcModuleSelection::all_modules());
376 }
377
378 #[test]
379 fn test_try_from_selection_success() {
380 let selection = vec!["eth", "admin"];
381 let config = RpcModuleSelection::try_from_selection(selection).unwrap();
382 assert_eq!(config, RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]));
383 }
384
385 #[test]
386 fn test_rpc_module_selection_len() {
387 let all_modules = RpcModuleSelection::All;
388 let standard = RpcModuleSelection::Standard;
389 let selection = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]);
390
391 assert_eq!(all_modules.len(), RethRpcModule::variant_count());
392 assert_eq!(standard.len(), 3);
393 assert_eq!(selection.len(), 2);
394 }
395
396 #[test]
397 fn test_rpc_module_selection_is_empty() {
398 let empty_selection = RpcModuleSelection::from(HashSet::new());
399 assert!(empty_selection.is_empty());
400
401 let non_empty_selection = RpcModuleSelection::from([RethRpcModule::Eth]);
402 assert!(!non_empty_selection.is_empty());
403 }
404
405 #[test]
406 fn test_rpc_module_selection_iter_selection() {
407 let all_modules = RpcModuleSelection::All;
408 let standard = RpcModuleSelection::Standard;
409 let selection = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]);
410
411 assert_eq!(all_modules.iter_selection().count(), RethRpcModule::variant_count());
412 assert_eq!(standard.iter_selection().count(), 3);
413 assert_eq!(selection.iter_selection().count(), 2);
414 }
415
416 #[test]
417 fn test_rpc_module_selection_to_selection() {
418 let all_modules = RpcModuleSelection::All;
419 let standard = RpcModuleSelection::Standard;
420 let selection = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]);
421
422 assert_eq!(all_modules.to_selection(), RpcModuleSelection::all_modules());
423 assert_eq!(standard.to_selection(), RpcModuleSelection::standard_modules());
424 assert_eq!(
425 selection.to_selection(),
426 HashSet::from([RethRpcModule::Eth, RethRpcModule::Admin])
427 );
428 }
429
430 #[test]
431 fn test_rpc_module_selection_are_identical() {
432 let all_modules = RpcModuleSelection::All;
437 assert!(RpcModuleSelection::are_identical(Some(&all_modules), Some(&all_modules)));
438
439 assert!(RpcModuleSelection::are_identical(None, None));
444
445 let selection1 = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]);
450 let selection2 = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]);
451 assert!(RpcModuleSelection::are_identical(Some(&selection1), Some(&selection2)));
452
453 let standard = RpcModuleSelection::Standard;
459 assert!(!RpcModuleSelection::are_identical(Some(&all_modules), Some(&standard)));
460
461 let empty_selection = RpcModuleSelection::Selection(HashSet::new());
466 assert!(RpcModuleSelection::are_identical(None, Some(&empty_selection)));
467 assert!(RpcModuleSelection::are_identical(Some(&empty_selection), None));
468
469 let non_empty_selection = RpcModuleSelection::from([RethRpcModule::Eth]);
475 assert!(!RpcModuleSelection::are_identical(None, Some(&non_empty_selection)));
476 assert!(!RpcModuleSelection::are_identical(Some(&non_empty_selection), None));
477
478 let partial_selection = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Net]);
483 assert!(!RpcModuleSelection::are_identical(Some(&all_modules), Some(&partial_selection)));
484
485 let full_selection =
490 RpcModuleSelection::from(RethRpcModule::modules().into_iter().collect::<HashSet<_>>());
491 assert!(RpcModuleSelection::are_identical(Some(&all_modules), Some(&full_selection)));
492
493 let selection3 = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Net]);
498 let selection4 = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Web3]);
499 assert!(!RpcModuleSelection::are_identical(Some(&selection3), Some(&selection4)));
500
501 let matching_standard =
505 RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Net, RethRpcModule::Web3]);
506 assert!(RpcModuleSelection::are_identical(Some(&standard), Some(&matching_standard)));
507
508 let non_matching_standard =
513 RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Net]);
514 assert!(!RpcModuleSelection::are_identical(Some(&standard), Some(&non_matching_standard)));
515 }
516
517 #[test]
518 fn test_rpc_module_selection_from_str() {
519 let result = RpcModuleSelection::from_str("");
521 assert!(result.is_ok());
522 assert_eq!(result.unwrap(), RpcModuleSelection::Selection(Default::default()));
523
524 let result = RpcModuleSelection::from_str("all");
526 assert!(result.is_ok());
527 assert_eq!(result.unwrap(), RpcModuleSelection::All);
528
529 let result = RpcModuleSelection::from_str("All");
530 assert!(result.is_ok());
531 assert_eq!(result.unwrap(), RpcModuleSelection::All);
532
533 let result = RpcModuleSelection::from_str("ALL");
534 assert!(result.is_ok());
535 assert_eq!(result.unwrap(), RpcModuleSelection::All);
536
537 let result = RpcModuleSelection::from_str("none");
539 assert!(result.is_ok());
540 assert_eq!(result.unwrap(), RpcModuleSelection::Selection(Default::default()));
541
542 let result = RpcModuleSelection::from_str("None");
543 assert!(result.is_ok());
544 assert_eq!(result.unwrap(), RpcModuleSelection::Selection(Default::default()));
545
546 let result = RpcModuleSelection::from_str("NONE");
547 assert!(result.is_ok());
548 assert_eq!(result.unwrap(), RpcModuleSelection::Selection(Default::default()));
549
550 let result = RpcModuleSelection::from_str("eth,admin");
552 assert!(result.is_ok());
553 let expected_selection =
554 RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]);
555 assert_eq!(result.unwrap(), expected_selection);
556
557 let result = RpcModuleSelection::from_str(" eth , admin ");
559 assert!(result.is_ok());
560 assert_eq!(result.unwrap(), expected_selection);
561
562 let result = RpcModuleSelection::from_str("invalid,unknown");
564 assert!(result.is_err());
565 assert_eq!(result.unwrap_err(), ParseError::VariantNotFound);
566
567 let result = RpcModuleSelection::from_str("eth");
569 assert!(result.is_ok());
570 let expected_selection = RpcModuleSelection::from([RethRpcModule::Eth]);
571 assert_eq!(result.unwrap(), expected_selection);
572
573 let result = RpcModuleSelection::from_str("unknown");
575 assert!(result.is_err());
576 assert_eq!(result.unwrap_err(), ParseError::VariantNotFound);
577 }
578}