1use std::{collections::HashSet, fmt, str::FromStr};
2
3use serde::{Deserialize, Serialize, Serializer};
4use strum::{ParseError, 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 Self::all_modules_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> {
46 Self::all_modules()
47 }
48
49 pub fn try_from_selection<I, T>(selection: I) -> Result<Self, T::Error>
75 where
76 I: IntoIterator<Item = T>,
77 T: TryInto<RethRpcModule>,
78 {
79 selection.into_iter().map(TryInto::try_into).collect()
80 }
81
82 pub fn len(&self) -> usize {
84 match self {
85 Self::All => Self::all_modules_iter().count(),
86 Self::Standard => Self::STANDARD_MODULES.len(),
87 Self::Selection(s) => s.len(),
88 }
89 }
90
91 pub fn is_empty(&self) -> bool {
93 match self {
94 Self::Selection(sel) => sel.is_empty(),
95 _ => false,
96 }
97 }
98
99 pub const fn is_all(&self) -> bool {
101 matches!(self, Self::All)
102 }
103
104 pub fn iter_selection(&self) -> Box<dyn Iterator<Item = RethRpcModule> + '_> {
106 match self {
107 Self::All => Box::new(Self::all_modules_iter()),
108 Self::Standard => Box::new(Self::STANDARD_MODULES.iter().cloned()),
109 Self::Selection(s) => Box::new(s.iter().cloned()),
110 }
111 }
112
113 pub fn to_selection(&self) -> HashSet<RethRpcModule> {
115 match self {
116 Self::All => Self::all_modules(),
117 Self::Standard => Self::standard_modules(),
118 Self::Selection(s) => s.clone(),
119 }
120 }
121
122 pub fn into_selection(self) -> HashSet<RethRpcModule> {
124 match self {
125 Self::All => Self::all_modules(),
126 Self::Standard => Self::standard_modules(),
127 Self::Selection(s) => s,
128 }
129 }
130
131 pub fn are_identical(http: Option<&Self>, ws: Option<&Self>) -> bool {
133 match (http, ws) {
134 (Some(some), None) | (None, Some(some)) => some.is_empty(),
136
137 (Some(http), Some(ws)) => http.to_selection() == ws.to_selection(),
138 (None, None) => true,
139 }
140 }
141
142 pub fn contains(&self, module: &RethRpcModule) -> bool {
144 match self {
145 Self::All => !matches!(module, RethRpcModule::Testing),
146 Self::Standard => Self::STANDARD_MODULES.contains(module),
147 Self::Selection(s) => s.contains(module),
148 }
149 }
150
151 pub fn push(&mut self, module: RethRpcModule) {
156 if !self.is_all() {
157 let mut modules = self.to_selection();
158 modules.insert(module);
159 *self = Self::Selection(modules);
160 }
161 }
162
163 pub fn append(self, module: RethRpcModule) -> Self {
168 if self.is_all() {
169 Self::All
170 } else {
171 let mut modules = self.into_selection();
172 modules.insert(module);
173 Self::Selection(modules)
174 }
175 }
176
177 pub fn extend<I>(&mut self, iter: I)
182 where
183 I: IntoIterator<Item = RethRpcModule>,
184 {
185 if !self.is_all() {
186 let mut modules = self.to_selection();
187 modules.extend(iter);
188 *self = Self::Selection(modules);
189 }
190 }
191
192 pub fn extended<I>(self, iter: I) -> Self
197 where
198 I: IntoIterator<Item = RethRpcModule>,
199 {
200 if self.is_all() {
201 Self::All
202 } else {
203 let mut modules = self.into_selection();
204 modules.extend(iter);
205 Self::Selection(modules)
206 }
207 }
208
209 fn all_modules_iter() -> impl Iterator<Item = RethRpcModule> {
210 RethRpcModule::modules().into_iter().filter(|module| *module != RethRpcModule::Testing)
211 }
212}
213
214impl From<&HashSet<RethRpcModule>> for RpcModuleSelection {
215 fn from(s: &HashSet<RethRpcModule>) -> Self {
216 Self::from(s.clone())
217 }
218}
219
220impl From<HashSet<RethRpcModule>> for RpcModuleSelection {
221 fn from(s: HashSet<RethRpcModule>) -> Self {
222 Self::Selection(s)
223 }
224}
225
226impl From<&[RethRpcModule]> for RpcModuleSelection {
227 fn from(s: &[RethRpcModule]) -> Self {
228 Self::Selection(s.iter().cloned().collect())
229 }
230}
231
232impl From<Vec<RethRpcModule>> for RpcModuleSelection {
233 fn from(s: Vec<RethRpcModule>) -> Self {
234 Self::Selection(s.into_iter().collect())
235 }
236}
237
238impl<const N: usize> From<[RethRpcModule; N]> for RpcModuleSelection {
239 fn from(s: [RethRpcModule; N]) -> Self {
240 Self::Selection(s.into_iter().collect())
241 }
242}
243
244impl<'a> FromIterator<&'a RethRpcModule> for RpcModuleSelection {
245 fn from_iter<I>(iter: I) -> Self
246 where
247 I: IntoIterator<Item = &'a RethRpcModule>,
248 {
249 iter.into_iter().cloned().collect()
250 }
251}
252
253impl FromIterator<RethRpcModule> for RpcModuleSelection {
254 fn from_iter<I>(iter: I) -> Self
255 where
256 I: IntoIterator<Item = RethRpcModule>,
257 {
258 Self::Selection(iter.into_iter().collect())
259 }
260}
261
262impl FromStr for RpcModuleSelection {
263 type Err = ParseError;
264
265 fn from_str(s: &str) -> Result<Self, Self::Err> {
266 if s.is_empty() {
267 return Ok(Self::Selection(Default::default()))
268 }
269 let mut modules = s.split(',').map(str::trim).peekable();
270 let first = modules.peek().copied().ok_or(ParseError::VariantNotFound)?;
271 match first.to_lowercase().as_str() {
275 "all" => Ok(Self::All),
276 "none" => Ok(Self::Selection(Default::default())),
277 _ => Self::try_from_selection(modules),
278 }
279 }
280}
281
282impl fmt::Display for RpcModuleSelection {
283 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
284 write!(
285 f,
286 "[{}]",
287 self.iter_selection().map(|s| s.to_string()).collect::<Vec<_>>().join(", ")
288 )
289 }
290}
291
292#[derive(Debug, Clone, Eq, PartialEq, Hash, VariantNames, Deserialize)]
294#[serde(rename_all = "snake_case")]
295#[strum(serialize_all = "kebab-case")]
296pub enum RethRpcModule {
297 Admin,
299 Debug,
301 Eth,
303 Net,
305 Trace,
307 Txpool,
309 Web3,
311 Rpc,
313 Reth,
315 Ots,
317 Flashbots,
319 Miner,
321 Mev,
323 Testing,
325 #[strum(default)]
327 #[serde(untagged)]
328 Other(String),
329}
330
331impl RethRpcModule {
334 const STANDARD_VARIANTS: &'static [Self] = &[
336 Self::Admin,
337 Self::Debug,
338 Self::Eth,
339 Self::Net,
340 Self::Trace,
341 Self::Txpool,
342 Self::Web3,
343 Self::Rpc,
344 Self::Reth,
345 Self::Ots,
346 Self::Flashbots,
347 Self::Miner,
348 Self::Mev,
349 Self::Testing,
350 ];
351
352 pub const fn variant_count() -> usize {
354 Self::STANDARD_VARIANTS.len()
355 }
356
357 pub const fn all_variant_names() -> &'static [&'static str] {
359 <Self as VariantNames>::VARIANTS
360 }
361
362 pub fn standard_variant_names() -> impl Iterator<Item = &'static str> {
364 <Self as VariantNames>::VARIANTS.iter().copied().filter(|&name| name != "other")
365 }
366
367 pub const fn all_variants() -> &'static [Self] {
369 Self::STANDARD_VARIANTS
370 }
371
372 pub fn modules() -> impl IntoIterator<Item = Self> + Clone {
374 Self::STANDARD_VARIANTS.iter().cloned()
375 }
376
377 pub fn as_str(&self) -> &str {
379 match self {
380 Self::Other(s) => s.as_str(),
381 _ => self.as_ref(), }
383 }
384
385 pub const fn is_other(&self) -> bool {
387 matches!(self, Self::Other(_))
388 }
389}
390
391impl AsRef<str> for RethRpcModule {
392 fn as_ref(&self) -> &str {
393 match self {
394 Self::Other(s) => s.as_str(),
395 Self::Admin => "admin",
397 Self::Debug => "debug",
398 Self::Eth => "eth",
399 Self::Net => "net",
400 Self::Trace => "trace",
401 Self::Txpool => "txpool",
402 Self::Web3 => "web3",
403 Self::Rpc => "rpc",
404 Self::Reth => "reth",
405 Self::Ots => "ots",
406 Self::Flashbots => "flashbots",
407 Self::Miner => "miner",
408 Self::Mev => "mev",
409 Self::Testing => "testing",
410 }
411 }
412}
413
414impl FromStr for RethRpcModule {
415 type Err = ParseError;
416
417 fn from_str(s: &str) -> Result<Self, Self::Err> {
418 Ok(match s {
419 "admin" => Self::Admin,
420 "debug" => Self::Debug,
421 "eth" => Self::Eth,
422 "net" => Self::Net,
423 "trace" => Self::Trace,
424 "txpool" => Self::Txpool,
425 "web3" => Self::Web3,
426 "rpc" => Self::Rpc,
427 "reth" => Self::Reth,
428 "ots" => Self::Ots,
429 "flashbots" => Self::Flashbots,
430 "miner" => Self::Miner,
431 "mev" => Self::Mev,
432 "testing" => Self::Testing,
433 other => Self::Other(other.to_string()),
435 })
436 }
437}
438
439impl TryFrom<&str> for RethRpcModule {
440 type Error = ParseError;
441 fn try_from(s: &str) -> Result<Self, <Self as TryFrom<&str>>::Error> {
442 FromStr::from_str(s)
443 }
444}
445
446impl fmt::Display for RethRpcModule {
447 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
448 f.pad(self.as_ref())
449 }
450}
451
452impl Serialize for RethRpcModule {
453 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
454 where
455 S: Serializer,
456 {
457 s.serialize_str(self.as_str())
458 }
459}
460
461pub trait RpcModuleValidator: Clone + Send + Sync + 'static {
466 fn parse_selection(s: &str) -> Result<RpcModuleSelection, String>;
468
469 fn validate_selection(modules: &RpcModuleSelection, arg_name: &str) -> Result<(), String> {
474 let RpcModuleSelection::Selection(module_set) = modules else {
478 return Ok(());
480 };
481
482 for module in module_set {
483 let RethRpcModule::Other(name) = module else {
484 continue;
486 };
487
488 Self::parse_selection(name)
491 .map_err(|e| format!("Invalid RPC module '{name}' in {arg_name}: {e}"))?;
492 }
493
494 Ok(())
495 }
496}
497
498#[derive(Debug, Clone, Copy)]
502pub struct DefaultRpcModuleValidator;
503
504impl RpcModuleValidator for DefaultRpcModuleValidator {
505 fn parse_selection(s: &str) -> Result<RpcModuleSelection, String> {
506 let selection = RpcModuleSelection::from_str(s)
508 .map_err(|e| format!("Failed to parse RPC modules: {}", e))?;
509
510 if let RpcModuleSelection::Selection(modules) = &selection {
512 for module in modules {
513 if let RethRpcModule::Other(name) = module {
514 return Err(format!("Unknown RPC module: '{}'", name));
515 }
516 }
517 }
518
519 Ok(selection)
520 }
521}
522
523#[derive(Debug, Clone, Copy)]
527pub struct LenientRpcModuleValidator;
528
529impl RpcModuleValidator for LenientRpcModuleValidator {
530 fn parse_selection(s: &str) -> Result<RpcModuleSelection, String> {
531 RpcModuleSelection::from_str(s).map_err(|e| format!("Failed to parse RPC modules: {}", e))
532 }
533}
534
535#[cfg(test)]
536mod test {
537 use super::*;
538
539 #[test]
540 fn test_all_modules() {
541 let all_modules = RpcModuleSelection::all_modules();
542 assert_eq!(all_modules.len(), RethRpcModule::variant_count() - 1);
543 assert!(!all_modules.contains(&RethRpcModule::Testing));
544 }
545
546 #[test]
547 fn test_testing_requires_explicit_selection() {
548 let all = RpcModuleSelection::All;
549 let explicit = RpcModuleSelection::from([RethRpcModule::Testing]);
550
551 assert!(!all.contains(&RethRpcModule::Testing));
552 assert!(!all.to_selection().contains(&RethRpcModule::Testing));
553 assert!(!all.into_selection().contains(&RethRpcModule::Testing));
554 assert!(explicit.contains(&RethRpcModule::Testing));
555 assert!(explicit.iter_selection().any(|module| module == RethRpcModule::Testing));
556 }
557
558 #[test]
559 fn test_standard_modules() {
560 let standard_modules = RpcModuleSelection::standard_modules();
561 let expected_modules: HashSet<RethRpcModule> =
562 HashSet::from([RethRpcModule::Eth, RethRpcModule::Net, RethRpcModule::Web3]);
563 assert_eq!(standard_modules, expected_modules);
564 }
565
566 #[test]
567 fn test_default_ipc_modules() {
568 let default_ipc_modules = RpcModuleSelection::default_ipc_modules();
569 assert_eq!(default_ipc_modules, RpcModuleSelection::all_modules());
570 assert!(!default_ipc_modules.contains(&RethRpcModule::Testing));
571 }
572
573 #[test]
574 fn test_try_from_selection_success() {
575 let selection = vec!["eth", "admin"];
576 let config = RpcModuleSelection::try_from_selection(selection).unwrap();
577 assert_eq!(config, RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]));
578 }
579
580 #[test]
581 fn test_rpc_module_selection_len() {
582 let all_modules = RpcModuleSelection::All;
583 let standard = RpcModuleSelection::Standard;
584 let selection = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]);
585
586 assert_eq!(all_modules.len(), RethRpcModule::variant_count() - 1);
587 assert_eq!(standard.len(), 3);
588 assert_eq!(selection.len(), 2);
589 }
590
591 #[test]
592 fn test_rpc_module_selection_is_empty() {
593 let empty_selection = RpcModuleSelection::from(HashSet::new());
594 assert!(empty_selection.is_empty());
595
596 let non_empty_selection = RpcModuleSelection::from([RethRpcModule::Eth]);
597 assert!(!non_empty_selection.is_empty());
598 }
599
600 #[test]
601 fn test_rpc_module_selection_iter_selection() {
602 let all_modules = RpcModuleSelection::All;
603 let standard = RpcModuleSelection::Standard;
604 let selection = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]);
605
606 assert_eq!(all_modules.iter_selection().count(), RethRpcModule::variant_count() - 1);
607 assert!(!all_modules.iter_selection().any(|module| module == RethRpcModule::Testing));
608 assert_eq!(standard.iter_selection().count(), 3);
609 assert_eq!(selection.iter_selection().count(), 2);
610 }
611
612 #[test]
613 fn test_rpc_module_selection_to_selection() {
614 let all_modules = RpcModuleSelection::All;
615 let standard = RpcModuleSelection::Standard;
616 let selection = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]);
617
618 assert_eq!(all_modules.to_selection(), RpcModuleSelection::all_modules());
619 assert_eq!(standard.to_selection(), RpcModuleSelection::standard_modules());
620 assert_eq!(
621 selection.to_selection(),
622 HashSet::from([RethRpcModule::Eth, RethRpcModule::Admin])
623 );
624 }
625
626 #[test]
627 fn test_rpc_module_selection_are_identical() {
628 let all_modules = RpcModuleSelection::All;
632 assert!(RpcModuleSelection::are_identical(Some(&all_modules), Some(&all_modules)));
633
634 assert!(RpcModuleSelection::are_identical(None, None));
639
640 let selection1 = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]);
645 let selection2 = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]);
646 assert!(RpcModuleSelection::are_identical(Some(&selection1), Some(&selection2)));
647
648 let standard = RpcModuleSelection::Standard;
654 assert!(!RpcModuleSelection::are_identical(Some(&all_modules), Some(&standard)));
655
656 let empty_selection = RpcModuleSelection::Selection(HashSet::new());
661 assert!(RpcModuleSelection::are_identical(None, Some(&empty_selection)));
662 assert!(RpcModuleSelection::are_identical(Some(&empty_selection), None));
663
664 let non_empty_selection = RpcModuleSelection::from([RethRpcModule::Eth]);
670 assert!(!RpcModuleSelection::are_identical(None, Some(&non_empty_selection)));
671 assert!(!RpcModuleSelection::are_identical(Some(&non_empty_selection), None));
672
673 let partial_selection = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Net]);
678 assert!(!RpcModuleSelection::are_identical(Some(&all_modules), Some(&partial_selection)));
679
680 let full_selection = RpcModuleSelection::from(RpcModuleSelection::all_modules());
684 assert!(RpcModuleSelection::are_identical(Some(&all_modules), Some(&full_selection)));
685
686 let mut testing_selection = RpcModuleSelection::all_modules();
688 testing_selection.insert(RethRpcModule::Testing);
689 let testing_selection = RpcModuleSelection::from(testing_selection);
690 assert!(!RpcModuleSelection::are_identical(Some(&all_modules), Some(&testing_selection),));
691
692 let selection3 = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Net]);
697 let selection4 = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Web3]);
698 assert!(!RpcModuleSelection::are_identical(Some(&selection3), Some(&selection4)));
699
700 let matching_standard =
704 RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Net, RethRpcModule::Web3]);
705 assert!(RpcModuleSelection::are_identical(Some(&standard), Some(&matching_standard)));
706
707 let non_matching_standard =
712 RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Net]);
713 assert!(!RpcModuleSelection::are_identical(Some(&standard), Some(&non_matching_standard)));
714 }
715
716 #[test]
717 fn test_rpc_module_selection_append() {
718 let selection = RpcModuleSelection::Standard;
720 let new_selection = selection.append(RethRpcModule::Admin);
721 assert!(new_selection.contains(&RethRpcModule::Eth));
722 assert!(new_selection.contains(&RethRpcModule::Net));
723 assert!(new_selection.contains(&RethRpcModule::Web3));
724 assert!(new_selection.contains(&RethRpcModule::Admin));
725
726 let selection = RpcModuleSelection::Selection(HashSet::new());
728 let new_selection = selection.append(RethRpcModule::Eth);
729 assert!(new_selection.contains(&RethRpcModule::Eth));
730 assert_eq!(new_selection.len(), 1);
731
732 let selection = RpcModuleSelection::All;
734 let new_selection = selection.append(RethRpcModule::Eth);
735 assert_eq!(new_selection, RpcModuleSelection::All);
736 }
737
738 #[test]
739 fn test_rpc_module_selection_extend() {
740 let mut selection = RpcModuleSelection::Standard;
742 selection.extend(vec![RethRpcModule::Admin, RethRpcModule::Debug]);
743 assert!(selection.contains(&RethRpcModule::Eth));
744 assert!(selection.contains(&RethRpcModule::Net));
745 assert!(selection.contains(&RethRpcModule::Web3));
746 assert!(selection.contains(&RethRpcModule::Admin));
747 assert!(selection.contains(&RethRpcModule::Debug));
748
749 let mut selection = RpcModuleSelection::Selection(HashSet::new());
751 selection.extend(vec![RethRpcModule::Eth, RethRpcModule::Admin]);
752 assert!(selection.contains(&RethRpcModule::Eth));
753 assert!(selection.contains(&RethRpcModule::Admin));
754 assert_eq!(selection.len(), 2);
755
756 let mut selection = RpcModuleSelection::All;
758 selection.extend(vec![RethRpcModule::Eth, RethRpcModule::Admin]);
759 assert_eq!(selection, RpcModuleSelection::All);
760 }
761
762 #[test]
763 fn test_rpc_module_selection_from_str() {
764 let result = RpcModuleSelection::from_str("");
766 assert!(result.is_ok());
767 assert_eq!(result.unwrap(), RpcModuleSelection::Selection(Default::default()));
768
769 let result = RpcModuleSelection::from_str("all");
771 assert!(result.is_ok());
772 assert_eq!(result.unwrap(), RpcModuleSelection::All);
773
774 let result = RpcModuleSelection::from_str("All");
775 assert!(result.is_ok());
776 assert_eq!(result.unwrap(), RpcModuleSelection::All);
777
778 let result = RpcModuleSelection::from_str("ALL");
779 assert!(result.is_ok());
780 assert_eq!(result.unwrap(), RpcModuleSelection::All);
781
782 let result = RpcModuleSelection::from_str("none");
784 assert!(result.is_ok());
785 assert_eq!(result.unwrap(), RpcModuleSelection::Selection(Default::default()));
786
787 let result = RpcModuleSelection::from_str("None");
788 assert!(result.is_ok());
789 assert_eq!(result.unwrap(), RpcModuleSelection::Selection(Default::default()));
790
791 let result = RpcModuleSelection::from_str("NONE");
792 assert!(result.is_ok());
793 assert_eq!(result.unwrap(), RpcModuleSelection::Selection(Default::default()));
794
795 let result = RpcModuleSelection::from_str("eth,admin");
797 assert!(result.is_ok());
798 let expected_selection =
799 RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]);
800 assert_eq!(result.unwrap(), expected_selection);
801
802 let result = RpcModuleSelection::from_str(" eth , admin ");
804 assert!(result.is_ok());
805 assert_eq!(result.unwrap(), expected_selection);
806
807 let result = RpcModuleSelection::from_str("invalid,unknown");
809 assert!(result.is_ok());
810 let selection = result.unwrap();
811 assert!(selection.contains(&RethRpcModule::Other("invalid".to_string())));
812 assert!(selection.contains(&RethRpcModule::Other("unknown".to_string())));
813
814 let result = RpcModuleSelection::from_str("eth");
816 assert!(result.is_ok());
817 let expected_selection = RpcModuleSelection::from([RethRpcModule::Eth]);
818 assert_eq!(result.unwrap(), expected_selection);
819
820 let result = RpcModuleSelection::from_str("unknown");
822 assert!(result.is_ok());
823 let expected_selection =
824 RpcModuleSelection::from([RethRpcModule::Other("unknown".to_string())]);
825 assert_eq!(result.unwrap(), expected_selection);
826 }
827
828 #[test]
829 fn test_rpc_module_other_variant() {
830 let custom_module = RethRpcModule::from_str("myCustomModule").unwrap();
832 assert_eq!(custom_module, RethRpcModule::Other("myCustomModule".to_string()));
833
834 assert_eq!(custom_module.as_str(), "myCustomModule");
836
837 assert_eq!(custom_module.as_ref(), "myCustomModule");
839
840 assert_eq!(custom_module.to_string(), "myCustomModule");
842 }
843
844 #[test]
845 fn test_rpc_module_selection_with_mixed_modules() {
846 let result = RpcModuleSelection::from_str("eth,admin,myCustomModule,anotherCustom");
848 assert!(result.is_ok());
849
850 let selection = result.unwrap();
851 assert!(selection.contains(&RethRpcModule::Eth));
852 assert!(selection.contains(&RethRpcModule::Admin));
853 assert!(selection.contains(&RethRpcModule::Other("myCustomModule".to_string())));
854 assert!(selection.contains(&RethRpcModule::Other("anotherCustom".to_string())));
855 }
856
857 #[test]
858 fn test_rpc_module_all_excludes_custom() {
859 let all_selection = RpcModuleSelection::All;
861
862 assert!(all_selection.contains(&RethRpcModule::Eth));
864 assert!(all_selection.contains(&RethRpcModule::Admin));
865
866 assert_eq!(all_selection.len(), RethRpcModule::variant_count() - 1);
869 }
870
871 #[test]
872 fn test_rpc_module_equality_with_other() {
873 let other1 = RethRpcModule::Other("custom".to_string());
874 let other2 = RethRpcModule::Other("custom".to_string());
875 let other3 = RethRpcModule::Other("different".to_string());
876
877 assert_eq!(other1, other2);
878 assert_ne!(other1, other3);
879 assert_ne!(other1, RethRpcModule::Eth);
880 }
881
882 #[test]
883 fn test_rpc_module_is_other() {
884 assert!(!RethRpcModule::Eth.is_other());
886 assert!(!RethRpcModule::Admin.is_other());
887 assert!(!RethRpcModule::Debug.is_other());
888
889 assert!(RethRpcModule::Other("custom".to_string()).is_other());
891 assert!(RethRpcModule::Other("mycustomrpc".to_string()).is_other());
892 }
893
894 #[test]
895 fn test_standard_variant_names_excludes_other() {
896 let standard_names: Vec<_> = RethRpcModule::standard_variant_names().collect();
897
898 assert!(!standard_names.contains(&"other"));
900
901 assert_eq!(standard_names.len(), RethRpcModule::STANDARD_VARIANTS.len());
903
904 for variant in RethRpcModule::STANDARD_VARIANTS {
906 assert!(standard_names.contains(&variant.as_ref()));
907 }
908 }
909
910 #[test]
911 fn test_default_validator_accepts_standard_modules() {
912 let result = DefaultRpcModuleValidator::parse_selection("eth,admin,debug");
914 assert!(result.is_ok());
915
916 let selection = result.unwrap();
917 assert!(matches!(selection, RpcModuleSelection::Selection(_)));
918 }
919
920 #[test]
921 fn test_default_validator_rejects_unknown_modules() {
922 let result = DefaultRpcModuleValidator::parse_selection("eth,mycustom");
924 assert!(result.is_err());
925 assert!(result.unwrap_err().contains("Unknown RPC module: 'mycustom'"));
926
927 let result = DefaultRpcModuleValidator::parse_selection("unknownmodule");
928 assert!(result.is_err());
929 assert!(result.unwrap_err().contains("Unknown RPC module: 'unknownmodule'"));
930
931 let result = DefaultRpcModuleValidator::parse_selection("eth,admin,xyz123");
932 assert!(result.is_err());
933 assert!(result.unwrap_err().contains("Unknown RPC module: 'xyz123'"));
934 }
935
936 #[test]
937 fn test_default_validator_all_selection() {
938 let result = DefaultRpcModuleValidator::parse_selection("all");
940 assert!(result.is_ok());
941 assert_eq!(result.unwrap(), RpcModuleSelection::All);
942 }
943
944 #[test]
945 fn test_default_validator_none_selection() {
946 let result = DefaultRpcModuleValidator::parse_selection("none");
948 assert!(result.is_ok());
949 assert_eq!(result.unwrap(), RpcModuleSelection::Selection(Default::default()));
950 }
951
952 #[test]
953 fn test_lenient_validator_accepts_unknown_modules() {
954 let result = LenientRpcModuleValidator::parse_selection("eht,adimn,xyz123,customrpc");
956 assert!(result.is_ok());
957
958 let selection = result.unwrap();
959 if let RpcModuleSelection::Selection(modules) = selection {
960 assert!(modules.contains(&RethRpcModule::Other("eht".to_string())));
961 assert!(modules.contains(&RethRpcModule::Other("adimn".to_string())));
962 assert!(modules.contains(&RethRpcModule::Other("xyz123".to_string())));
963 assert!(modules.contains(&RethRpcModule::Other("customrpc".to_string())));
964 } else {
965 panic!("Expected Selection variant");
966 }
967 }
968
969 #[test]
970 fn test_default_validator_mixed_standard_and_custom() {
971 let result = DefaultRpcModuleValidator::parse_selection("eth,admin,mycustom,debug");
973 assert!(result.is_err());
974 assert!(result.unwrap_err().contains("Unknown RPC module: 'mycustom'"));
975 }
976}