reth_eth_wire_types/
capability.rs
1use crate::EthVersion;
4use alloc::{borrow::Cow, string::String, vec::Vec};
5use alloy_rlp::{Decodable, Encodable, RlpDecodable, RlpEncodable};
6use bytes::BufMut;
7use core::fmt;
8use reth_codecs_derive::add_arbitrary_tests;
9
10#[add_arbitrary_tests(rlp)]
12#[derive(Clone, Debug, PartialEq, Eq, RlpEncodable, RlpDecodable, Default, Hash)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct Capability {
15 pub name: Cow<'static, str>,
17 pub version: usize,
19}
20
21impl Capability {
22 pub const fn new(name: String, version: usize) -> Self {
24 Self { name: Cow::Owned(name), version }
25 }
26
27 pub const fn new_static(name: &'static str, version: usize) -> Self {
29 Self { name: Cow::Borrowed(name), version }
30 }
31
32 pub const fn eth(version: EthVersion) -> Self {
34 Self::new_static("eth", version as usize)
35 }
36
37 pub const fn eth_66() -> Self {
39 Self::eth(EthVersion::Eth66)
40 }
41
42 pub const fn eth_67() -> Self {
44 Self::eth(EthVersion::Eth67)
45 }
46
47 pub const fn eth_68() -> Self {
49 Self::eth(EthVersion::Eth68)
50 }
51
52 #[inline]
54 pub fn is_eth_v66(&self) -> bool {
55 self.name == "eth" && self.version == 66
56 }
57
58 #[inline]
60 pub fn is_eth_v67(&self) -> bool {
61 self.name == "eth" && self.version == 67
62 }
63
64 #[inline]
66 pub fn is_eth_v68(&self) -> bool {
67 self.name == "eth" && self.version == 68
68 }
69
70 #[inline]
72 pub fn is_eth(&self) -> bool {
73 self.is_eth_v66() || self.is_eth_v67() || self.is_eth_v68()
74 }
75}
76
77impl fmt::Display for Capability {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 write!(f, "{}/{}", self.name, self.version)
80 }
81}
82
83impl From<EthVersion> for Capability {
84 #[inline]
85 fn from(value: EthVersion) -> Self {
86 Self::eth(value)
87 }
88}
89
90#[cfg(any(test, feature = "arbitrary"))]
91impl<'a> arbitrary::Arbitrary<'a> for Capability {
92 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
93 let version = u.int_in_range(66..=69)?; Ok(Self::new_static("eth", version))
96 }
97}
98
99#[derive(Debug, Clone, Eq, PartialEq)]
101pub struct Capabilities {
102 inner: Vec<Capability>,
104 eth_66: bool,
105 eth_67: bool,
106 eth_68: bool,
107}
108
109impl Capabilities {
110 #[inline]
112 pub fn capabilities(&self) -> &[Capability] {
113 &self.inner
114 }
115
116 #[inline]
118 pub fn into_inner(self) -> Vec<Capability> {
119 self.inner
120 }
121
122 #[inline]
124 pub const fn supports_eth(&self) -> bool {
125 self.eth_68 || self.eth_67 || self.eth_66
126 }
127
128 #[inline]
130 pub const fn supports_eth_v66(&self) -> bool {
131 self.eth_66
132 }
133
134 #[inline]
136 pub const fn supports_eth_v67(&self) -> bool {
137 self.eth_67
138 }
139
140 #[inline]
142 pub const fn supports_eth_v68(&self) -> bool {
143 self.eth_68
144 }
145}
146
147impl From<Vec<Capability>> for Capabilities {
148 fn from(value: Vec<Capability>) -> Self {
149 Self {
150 eth_66: value.iter().any(Capability::is_eth_v66),
151 eth_67: value.iter().any(Capability::is_eth_v67),
152 eth_68: value.iter().any(Capability::is_eth_v68),
153 inner: value,
154 }
155 }
156}
157
158impl Encodable for Capabilities {
159 fn encode(&self, out: &mut dyn BufMut) {
160 self.inner.encode(out)
161 }
162}
163
164impl Decodable for Capabilities {
165 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
166 let inner = Vec::<Capability>::decode(buf)?;
167
168 Ok(Self {
169 eth_66: inner.iter().any(Capability::is_eth_v66),
170 eth_67: inner.iter().any(Capability::is_eth_v67),
171 eth_68: inner.iter().any(Capability::is_eth_v68),
172 inner,
173 })
174 }
175}