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 const fn is_all(&self) -> bool {
103 matches!(self, Self::All)
104 }
105
106 pub fn iter_selection(&self) -> Box<dyn Iterator<Item = RethRpcModule> + '_> {
108 match self {
109 Self::All => Box::new(RethRpcModule::modules().into_iter()),
110 Self::Standard => Box::new(Self::STANDARD_MODULES.iter().copied()),
111 Self::Selection(s) => Box::new(s.iter().copied()),
112 }
113 }
114
115 pub fn to_selection(&self) -> HashSet<RethRpcModule> {
117 match self {
118 Self::All => Self::all_modules(),
119 Self::Standard => Self::standard_modules(),
120 Self::Selection(s) => s.clone(),
121 }
122 }
123
124 pub fn into_selection(self) -> HashSet<RethRpcModule> {
126 match self {
127 Self::All => Self::all_modules(),
128 Self::Standard => Self::standard_modules(),
129 Self::Selection(s) => s,
130 }
131 }
132
133 pub fn are_identical(http: Option<&Self>, ws: Option<&Self>) -> bool {
135 match (http, ws) {
136 (Some(Self::All), Some(other)) | (Some(other), Some(Self::All)) => {
138 other.len() == RethRpcModule::variant_count()
139 }
140
141 (Some(some), None) | (None, Some(some)) => some.is_empty(),
143
144 (Some(http), Some(ws)) => http.to_selection() == ws.to_selection(),
145 (None, None) => true,
146 }
147 }
148
149 pub fn contains(&self, module: &RethRpcModule) -> bool {
151 match self {
152 Self::All => true,
153 Self::Standard => Self::STANDARD_MODULES.contains(module),
154 Self::Selection(s) => s.contains(module),
155 }
156 }
157
158 pub fn push(&mut self, module: RethRpcModule) {
163 if !self.is_all() {
164 let mut modules = self.to_selection();
165 modules.insert(module);
166 *self = Self::Selection(modules);
167 }
168 }
169
170 pub fn append(self, module: RethRpcModule) -> Self {
175 if self.is_all() {
176 Self::All
177 } else {
178 let mut modules = self.into_selection();
179 modules.insert(module);
180 Self::Selection(modules)
181 }
182 }
183
184 pub fn extend<I>(&mut self, iter: I)
189 where
190 I: IntoIterator<Item = RethRpcModule>,
191 {
192 if !self.is_all() {
193 let mut modules = self.to_selection();
194 modules.extend(iter);
195 *self = Self::Selection(modules);
196 }
197 }
198
199 pub fn extended<I>(self, iter: I) -> Self
204 where
205 I: IntoIterator<Item = RethRpcModule>,
206 {
207 if self.is_all() {
208 Self::All
209 } else {
210 let mut modules = self.into_selection();
211 modules.extend(iter);
212 Self::Selection(modules)
213 }
214 }
215}
216
217impl From<&HashSet<RethRpcModule>> for RpcModuleSelection {
218 fn from(s: &HashSet<RethRpcModule>) -> Self {
219 Self::from(s.clone())
220 }
221}
222
223impl From<HashSet<RethRpcModule>> for RpcModuleSelection {
224 fn from(s: HashSet<RethRpcModule>) -> Self {
225 Self::Selection(s)
226 }
227}
228
229impl From<&[RethRpcModule]> for RpcModuleSelection {
230 fn from(s: &[RethRpcModule]) -> Self {
231 Self::Selection(s.iter().copied().collect())
232 }
233}
234
235impl From<Vec<RethRpcModule>> for RpcModuleSelection {
236 fn from(s: Vec<RethRpcModule>) -> Self {
237 Self::Selection(s.into_iter().collect())
238 }
239}
240
241impl<const N: usize> From<[RethRpcModule; N]> for RpcModuleSelection {
242 fn from(s: [RethRpcModule; N]) -> Self {
243 Self::Selection(s.iter().copied().collect())
244 }
245}
246
247impl<'a> FromIterator<&'a RethRpcModule> for RpcModuleSelection {
248 fn from_iter<I>(iter: I) -> Self
249 where
250 I: IntoIterator<Item = &'a RethRpcModule>,
251 {
252 iter.into_iter().copied().collect()
253 }
254}
255
256impl FromIterator<RethRpcModule> for RpcModuleSelection {
257 fn from_iter<I>(iter: I) -> Self
258 where
259 I: IntoIterator<Item = RethRpcModule>,
260 {
261 Self::Selection(iter.into_iter().collect())
262 }
263}
264
265impl FromStr for RpcModuleSelection {
266 type Err = ParseError;
267
268 fn from_str(s: &str) -> Result<Self, Self::Err> {
269 if s.is_empty() {
270 return Ok(Self::Selection(Default::default()))
271 }
272 let mut modules = s.split(',').map(str::trim).peekable();
273 let first = modules.peek().copied().ok_or(ParseError::VariantNotFound)?;
274 match first.to_lowercase().as_str() {
278 "all" => Ok(Self::All),
279 "none" => Ok(Self::Selection(Default::default())),
280 _ => Self::try_from_selection(modules),
281 }
282 }
283}
284
285impl fmt::Display for RpcModuleSelection {
286 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
287 write!(
288 f,
289 "[{}]",
290 self.iter_selection().map(|s| s.to_string()).collect::<Vec<_>>().join(", ")
291 )
292 }
293}
294
295#[derive(
297 Debug,
298 Clone,
299 Copy,
300 Eq,
301 PartialEq,
302 Hash,
303 AsRefStr,
304 IntoStaticStr,
305 VariantNames,
306 VariantArray,
307 EnumIter,
308 Deserialize,
309)]
310#[serde(rename_all = "snake_case")]
311#[strum(serialize_all = "kebab-case")]
312pub enum RethRpcModule {
313 Admin,
315 Debug,
317 Eth,
319 Net,
321 Trace,
323 Txpool,
325 Web3,
327 Rpc,
329 Reth,
331 Ots,
333 Flashbots,
335 Miner,
337 Mev,
339}
340
341impl RethRpcModule {
344 pub const fn variant_count() -> usize {
346 <Self as VariantArray>::VARIANTS.len()
347 }
348
349 pub const fn all_variant_names() -> &'static [&'static str] {
351 <Self as VariantNames>::VARIANTS
352 }
353
354 pub const fn all_variants() -> &'static [Self] {
356 <Self as VariantArray>::VARIANTS
357 }
358
359 pub fn modules() -> impl IntoIterator<Item = Self> {
361 use strum::IntoEnumIterator;
362 Self::iter()
363 }
364
365 #[inline]
367 pub fn as_str(&self) -> &'static str {
368 self.into()
369 }
370}
371
372impl FromStr for RethRpcModule {
373 type Err = ParseError;
374
375 fn from_str(s: &str) -> Result<Self, Self::Err> {
376 Ok(match s {
377 "admin" => Self::Admin,
378 "debug" => Self::Debug,
379 "eth" => Self::Eth,
380 "net" => Self::Net,
381 "trace" => Self::Trace,
382 "txpool" => Self::Txpool,
383 "web3" => Self::Web3,
384 "rpc" => Self::Rpc,
385 "reth" => Self::Reth,
386 "ots" => Self::Ots,
387 "flashbots" => Self::Flashbots,
388 "miner" => Self::Miner,
389 "mev" => Self::Mev,
390 _ => return Err(ParseError::VariantNotFound),
391 })
392 }
393}
394
395impl TryFrom<&str> for RethRpcModule {
396 type Error = ParseError;
397 fn try_from(s: &str) -> Result<Self, <Self as TryFrom<&str>>::Error> {
398 FromStr::from_str(s)
399 }
400}
401
402impl fmt::Display for RethRpcModule {
403 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
404 f.pad(self.as_ref())
405 }
406}
407
408impl Serialize for RethRpcModule {
409 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
410 where
411 S: Serializer,
412 {
413 s.serialize_str(self.as_ref())
414 }
415}
416
417#[cfg(test)]
418mod test {
419 use super::*;
420
421 #[test]
422 fn test_all_modules() {
423 let all_modules = RpcModuleSelection::all_modules();
424 assert_eq!(all_modules.len(), RethRpcModule::variant_count());
425 }
426
427 #[test]
428 fn test_standard_modules() {
429 let standard_modules = RpcModuleSelection::standard_modules();
430 let expected_modules: HashSet<RethRpcModule> =
431 HashSet::from([RethRpcModule::Eth, RethRpcModule::Net, RethRpcModule::Web3]);
432 assert_eq!(standard_modules, expected_modules);
433 }
434
435 #[test]
436 fn test_default_ipc_modules() {
437 let default_ipc_modules = RpcModuleSelection::default_ipc_modules();
438 assert_eq!(default_ipc_modules, RpcModuleSelection::all_modules());
439 }
440
441 #[test]
442 fn test_try_from_selection_success() {
443 let selection = vec!["eth", "admin"];
444 let config = RpcModuleSelection::try_from_selection(selection).unwrap();
445 assert_eq!(config, RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]));
446 }
447
448 #[test]
449 fn test_rpc_module_selection_len() {
450 let all_modules = RpcModuleSelection::All;
451 let standard = RpcModuleSelection::Standard;
452 let selection = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]);
453
454 assert_eq!(all_modules.len(), RethRpcModule::variant_count());
455 assert_eq!(standard.len(), 3);
456 assert_eq!(selection.len(), 2);
457 }
458
459 #[test]
460 fn test_rpc_module_selection_is_empty() {
461 let empty_selection = RpcModuleSelection::from(HashSet::new());
462 assert!(empty_selection.is_empty());
463
464 let non_empty_selection = RpcModuleSelection::from([RethRpcModule::Eth]);
465 assert!(!non_empty_selection.is_empty());
466 }
467
468 #[test]
469 fn test_rpc_module_selection_iter_selection() {
470 let all_modules = RpcModuleSelection::All;
471 let standard = RpcModuleSelection::Standard;
472 let selection = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]);
473
474 assert_eq!(all_modules.iter_selection().count(), RethRpcModule::variant_count());
475 assert_eq!(standard.iter_selection().count(), 3);
476 assert_eq!(selection.iter_selection().count(), 2);
477 }
478
479 #[test]
480 fn test_rpc_module_selection_to_selection() {
481 let all_modules = RpcModuleSelection::All;
482 let standard = RpcModuleSelection::Standard;
483 let selection = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]);
484
485 assert_eq!(all_modules.to_selection(), RpcModuleSelection::all_modules());
486 assert_eq!(standard.to_selection(), RpcModuleSelection::standard_modules());
487 assert_eq!(
488 selection.to_selection(),
489 HashSet::from([RethRpcModule::Eth, RethRpcModule::Admin])
490 );
491 }
492
493 #[test]
494 fn test_rpc_module_selection_are_identical() {
495 let all_modules = RpcModuleSelection::All;
500 assert!(RpcModuleSelection::are_identical(Some(&all_modules), Some(&all_modules)));
501
502 assert!(RpcModuleSelection::are_identical(None, None));
507
508 let selection1 = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]);
513 let selection2 = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]);
514 assert!(RpcModuleSelection::are_identical(Some(&selection1), Some(&selection2)));
515
516 let standard = RpcModuleSelection::Standard;
522 assert!(!RpcModuleSelection::are_identical(Some(&all_modules), Some(&standard)));
523
524 let empty_selection = RpcModuleSelection::Selection(HashSet::new());
529 assert!(RpcModuleSelection::are_identical(None, Some(&empty_selection)));
530 assert!(RpcModuleSelection::are_identical(Some(&empty_selection), None));
531
532 let non_empty_selection = RpcModuleSelection::from([RethRpcModule::Eth]);
538 assert!(!RpcModuleSelection::are_identical(None, Some(&non_empty_selection)));
539 assert!(!RpcModuleSelection::are_identical(Some(&non_empty_selection), None));
540
541 let partial_selection = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Net]);
546 assert!(!RpcModuleSelection::are_identical(Some(&all_modules), Some(&partial_selection)));
547
548 let full_selection =
553 RpcModuleSelection::from(RethRpcModule::modules().into_iter().collect::<HashSet<_>>());
554 assert!(RpcModuleSelection::are_identical(Some(&all_modules), Some(&full_selection)));
555
556 let selection3 = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Net]);
561 let selection4 = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Web3]);
562 assert!(!RpcModuleSelection::are_identical(Some(&selection3), Some(&selection4)));
563
564 let matching_standard =
568 RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Net, RethRpcModule::Web3]);
569 assert!(RpcModuleSelection::are_identical(Some(&standard), Some(&matching_standard)));
570
571 let non_matching_standard =
576 RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Net]);
577 assert!(!RpcModuleSelection::are_identical(Some(&standard), Some(&non_matching_standard)));
578 }
579
580 #[test]
581 fn test_rpc_module_selection_append() {
582 let selection = RpcModuleSelection::Standard;
584 let new_selection = selection.append(RethRpcModule::Admin);
585 assert!(new_selection.contains(&RethRpcModule::Eth));
586 assert!(new_selection.contains(&RethRpcModule::Net));
587 assert!(new_selection.contains(&RethRpcModule::Web3));
588 assert!(new_selection.contains(&RethRpcModule::Admin));
589
590 let selection = RpcModuleSelection::Selection(HashSet::new());
592 let new_selection = selection.append(RethRpcModule::Eth);
593 assert!(new_selection.contains(&RethRpcModule::Eth));
594 assert_eq!(new_selection.len(), 1);
595
596 let selection = RpcModuleSelection::All;
598 let new_selection = selection.append(RethRpcModule::Eth);
599 assert_eq!(new_selection, RpcModuleSelection::All);
600 }
601
602 #[test]
603 fn test_rpc_module_selection_extend() {
604 let mut selection = RpcModuleSelection::Standard;
606 selection.extend(vec![RethRpcModule::Admin, RethRpcModule::Debug]);
607 assert!(selection.contains(&RethRpcModule::Eth));
608 assert!(selection.contains(&RethRpcModule::Net));
609 assert!(selection.contains(&RethRpcModule::Web3));
610 assert!(selection.contains(&RethRpcModule::Admin));
611 assert!(selection.contains(&RethRpcModule::Debug));
612
613 let mut selection = RpcModuleSelection::Selection(HashSet::new());
615 selection.extend(vec![RethRpcModule::Eth, RethRpcModule::Admin]);
616 assert!(selection.contains(&RethRpcModule::Eth));
617 assert!(selection.contains(&RethRpcModule::Admin));
618 assert_eq!(selection.len(), 2);
619
620 let mut selection = RpcModuleSelection::All;
622 selection.extend(vec![RethRpcModule::Eth, RethRpcModule::Admin]);
623 assert_eq!(selection, RpcModuleSelection::All);
624 }
625
626 #[test]
627 fn test_rpc_module_selection_from_str() {
628 let result = RpcModuleSelection::from_str("");
630 assert!(result.is_ok());
631 assert_eq!(result.unwrap(), RpcModuleSelection::Selection(Default::default()));
632
633 let result = RpcModuleSelection::from_str("all");
635 assert!(result.is_ok());
636 assert_eq!(result.unwrap(), RpcModuleSelection::All);
637
638 let result = RpcModuleSelection::from_str("All");
639 assert!(result.is_ok());
640 assert_eq!(result.unwrap(), RpcModuleSelection::All);
641
642 let result = RpcModuleSelection::from_str("ALL");
643 assert!(result.is_ok());
644 assert_eq!(result.unwrap(), RpcModuleSelection::All);
645
646 let result = RpcModuleSelection::from_str("none");
648 assert!(result.is_ok());
649 assert_eq!(result.unwrap(), RpcModuleSelection::Selection(Default::default()));
650
651 let result = RpcModuleSelection::from_str("None");
652 assert!(result.is_ok());
653 assert_eq!(result.unwrap(), RpcModuleSelection::Selection(Default::default()));
654
655 let result = RpcModuleSelection::from_str("NONE");
656 assert!(result.is_ok());
657 assert_eq!(result.unwrap(), RpcModuleSelection::Selection(Default::default()));
658
659 let result = RpcModuleSelection::from_str("eth,admin");
661 assert!(result.is_ok());
662 let expected_selection =
663 RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]);
664 assert_eq!(result.unwrap(), expected_selection);
665
666 let result = RpcModuleSelection::from_str(" eth , admin ");
668 assert!(result.is_ok());
669 assert_eq!(result.unwrap(), expected_selection);
670
671 let result = RpcModuleSelection::from_str("invalid,unknown");
673 assert!(result.is_err());
674 assert_eq!(result.unwrap_err(), ParseError::VariantNotFound);
675
676 let result = RpcModuleSelection::from_str("eth");
678 assert!(result.is_ok());
679 let expected_selection = RpcModuleSelection::from([RethRpcModule::Eth]);
680 assert_eq!(result.unwrap(), expected_selection);
681
682 let result = RpcModuleSelection::from_str("unknown");
684 assert!(result.is_err());
685 assert_eq!(result.unwrap_err(), ParseError::VariantNotFound);
686 }
687}