1use std::{collections::HashSet, fmt, str::FromStr};
30
31use serde::{Deserialize, Serialize, Serializer};
32use strum::{
33 AsRefStr, EnumIter, IntoStaticStr, ParseError, VariantArray, VariantNames,
34};
35
36#[derive(Debug, Default, Clone, Eq, PartialEq)]
38pub enum RpcModuleSelection {
39 All,
41 #[default]
43 Standard,
44 Evm,
46 Selection(HashSet<EthRpcModule>),
48}
49
50impl RpcModuleSelection {
51 pub const EVM_MODULES: [EthRpcModule; 6] = [
52 EthRpcModule::Eth,
53 EthRpcModule::PubSub,
54 EthRpcModule::Net,
55 EthRpcModule::Web3,
56 EthRpcModule::Parity,
57 EthRpcModule::Trace,
58 ];
59 pub const STANDARD_MODULES: [EthRpcModule; 3] =
61 [EthRpcModule::Eth, EthRpcModule::Net, EthRpcModule::Web3];
62
63 pub fn all_modules() -> HashSet<EthRpcModule> {
66 EthRpcModule::modules().into_iter().collect()
67 }
68
69 pub fn standard_modules() -> HashSet<EthRpcModule> {
71 HashSet::from(Self::STANDARD_MODULES)
72 }
73
74 pub fn evm_modules() -> HashSet<EthRpcModule> {
75 HashSet::from(Self::EVM_MODULES)
76 }
77
78 pub fn default_ipc_modules() -> HashSet<EthRpcModule> {
82 Self::all_modules()
83 }
84
85 pub fn try_from_selection<I, T>(selection: I) -> Result<Self, T::Error>
93 where
94 I: IntoIterator<Item = T>,
95 T: TryInto<EthRpcModule>,
96 {
97 selection.into_iter().map(TryInto::try_into).collect()
98 }
99
100 pub fn len(&self) -> usize {
102 match self {
103 Self::All => EthRpcModule::variant_count(),
104 Self::Standard => Self::STANDARD_MODULES.len(),
105 Self::Evm => Self::EVM_MODULES.len(),
106 Self::Selection(s) => s.len(),
107 }
108 }
109
110 pub fn is_empty(&self) -> bool {
112 match self {
113 Self::Selection(sel) => sel.is_empty(),
114 _ => false,
115 }
116 }
117
118 pub fn iter_selection(
120 &self,
121 ) -> Box<dyn Iterator<Item = EthRpcModule> + '_> {
122 match self {
123 Self::All => Box::new(EthRpcModule::modules().into_iter()),
124 Self::Standard => Box::new(Self::STANDARD_MODULES.iter().copied()),
125 Self::Evm => Box::new(Self::EVM_MODULES.iter().copied()),
126 Self::Selection(s) => Box::new(s.iter().copied()),
127 }
128 }
129
130 pub fn to_selection(&self) -> HashSet<EthRpcModule> {
132 match self {
133 Self::All => Self::all_modules(),
134 Self::Standard => Self::standard_modules(),
135 Self::Evm => Self::evm_modules(),
136 Self::Selection(s) => s.clone(),
137 }
138 }
139
140 pub fn into_selection(self) -> HashSet<EthRpcModule> {
142 match self {
143 Self::All => Self::all_modules(),
144 Self::Standard => Self::standard_modules(),
145 Self::Evm => Self::evm_modules(),
146 Self::Selection(s) => s,
147 }
148 }
149
150 pub fn are_identical(http: Option<&Self>, ws: Option<&Self>) -> bool {
152 match (http, ws) {
153 (Some(Self::All), Some(other)) | (Some(other), Some(Self::All)) => {
155 other.len() == EthRpcModule::variant_count()
156 }
157
158 (Some(some), None) | (None, Some(some)) => some.is_empty(),
160
161 (Some(http), Some(ws)) => http.to_selection() == ws.to_selection(),
162 (None, None) => true,
163 }
164 }
165}
166
167impl From<&HashSet<EthRpcModule>> for RpcModuleSelection {
168 fn from(s: &HashSet<EthRpcModule>) -> Self { Self::from(s.clone()) }
169}
170
171impl From<HashSet<EthRpcModule>> for RpcModuleSelection {
172 fn from(s: HashSet<EthRpcModule>) -> Self { Self::Selection(s) }
173}
174
175impl From<&[EthRpcModule]> for RpcModuleSelection {
176 fn from(s: &[EthRpcModule]) -> Self {
177 Self::Selection(s.iter().copied().collect())
178 }
179}
180
181impl From<Vec<EthRpcModule>> for RpcModuleSelection {
182 fn from(s: Vec<EthRpcModule>) -> Self {
183 Self::Selection(s.into_iter().collect())
184 }
185}
186
187impl<const N: usize> From<[EthRpcModule; N]> for RpcModuleSelection {
188 fn from(s: [EthRpcModule; N]) -> Self {
189 Self::Selection(s.iter().copied().collect())
190 }
191}
192
193impl<'a> FromIterator<&'a EthRpcModule> for RpcModuleSelection {
194 fn from_iter<I>(iter: I) -> Self
195 where I: IntoIterator<Item = &'a EthRpcModule> {
196 iter.into_iter().copied().collect()
197 }
198}
199
200impl FromIterator<EthRpcModule> for RpcModuleSelection {
201 fn from_iter<I>(iter: I) -> Self
202 where I: IntoIterator<Item = EthRpcModule> {
203 Self::Selection(iter.into_iter().collect())
204 }
205}
206
207impl FromStr for RpcModuleSelection {
208 type Err = String;
209
210 fn from_str(s: &str) -> Result<Self, Self::Err> {
211 if s.is_empty() {
212 return Ok(Self::Selection(Default::default()));
213 }
214 let mut modules = s.split(',').map(str::trim).peekable();
215 let first = modules
216 .peek()
217 .copied()
218 .ok_or(ParseError::VariantNotFound.to_string())?;
219 match first {
220 "all" | "All" => Ok(Self::All),
221 "none" | "None" => Ok(Self::Selection(Default::default())),
222 "standard" | "Standard" => Ok(Self::Standard),
223 "evm" | "Evm" => Ok(Self::Evm),
224 _ => Self::try_from_selection(modules).map_err(|e| e.to_string()),
225 }
226 }
227}
228
229impl fmt::Display for RpcModuleSelection {
230 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231 write!(
232 f,
233 "[{}]",
234 self.iter_selection()
235 .map(|s| s.to_string())
236 .collect::<Vec<_>>()
237 .join(", ")
238 )
239 }
240}
241
242#[derive(
243 Debug,
244 Clone,
245 Copy,
246 Eq,
247 PartialEq,
248 Hash,
249 AsRefStr,
250 IntoStaticStr,
251 VariantNames,
252 VariantArray,
253 EnumIter,
254 Deserialize,
255)]
256#[serde(rename_all = "snake_case")]
257#[strum(serialize_all = "kebab-case")]
258pub enum EthRpcModule {
259 Debug,
263 Eth,
265 Net,
267 Trace,
269 Txpool,
271 Web3,
273 Rpc,
275 Parity,
277 PubSub,
279}
280
281impl EthRpcModule {
282 pub const fn variant_count() -> usize {
284 <Self as VariantArray>::VARIANTS.len()
285 }
286
287 pub const fn all_variant_names() -> &'static [&'static str] {
289 <Self as VariantNames>::VARIANTS
290 }
291
292 pub const fn all_variants() -> &'static [Self] {
294 <Self as VariantArray>::VARIANTS
295 }
296
297 pub fn modules() -> impl IntoIterator<Item = Self> {
299 use strum::IntoEnumIterator;
300 Self::iter()
301 }
302
303 #[inline]
305 pub fn as_str(&self) -> &'static str { self.into() }
306}
307
308impl FromStr for EthRpcModule {
309 type Err = ParseError;
310
311 fn from_str(s: &str) -> Result<Self, Self::Err> {
312 Ok(match s {
313 "debug" | "ethdebug" => Self::Debug,
315 "eth" => Self::Eth,
316 "net" => Self::Net,
317 "trace" => Self::Trace,
318 "txpool" => Self::Txpool,
319 "web3" => Self::Web3,
320 "rpc" => Self::Rpc,
321 "parity" => Self::Parity,
322 "pubsub" | "ethpubsub" => Self::PubSub,
323 _ => return Err(ParseError::VariantNotFound),
324 })
325 }
326}
327
328impl TryFrom<&str> for EthRpcModule {
329 type Error = ParseError;
330
331 fn try_from(s: &str) -> Result<Self, <Self as TryFrom<&str>>::Error> {
332 FromStr::from_str(s)
333 }
334}
335
336impl fmt::Display for EthRpcModule {
337 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
338 f.pad(self.as_ref())
339 }
340}
341
342impl Serialize for EthRpcModule {
343 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
344 where S: Serializer {
345 s.serialize_str(self.as_ref())
346 }
347}