tor_cell/
restrict.rs
1pub use {paste, tor_bytes};
5
6#[macro_export]
40macro_rules! restricted_msg {
41 {
42 $(#[$meta:meta])*
43 $(@omit_from $omit_from:literal)?
44 $v:vis enum $name:ident : RelayMsg {
45 $($tt:tt)*
46 }
47 } => {
48 $crate::restrict::restricted_msg!{
49 [
50 any_type: $crate::relaycell::msg::AnyRelayMsg,
51 msg_mod: $crate::relaycell::msg,
52 cmd_type: $crate::relaycell::RelayCmd,
53 unrecognized: $crate::relaycell::msg::Unrecognized,
54 body_trait: $crate::relaycell::msg::Body,
55 msg_trait: $crate::relaycell::RelayMsg,
56 omit_from: $($omit_from)?
57 ]
58 $(#[$meta])*
59 $v enum $name { $($tt)*}
60 }
61 };
62 {
63 $(#[$meta:meta])*
64 $(@omit_from $omit_from:literal)?
65 $v:vis enum $name:ident : ChanMsg {
66 $($tt:tt)*
67 }
68 } => {
69 $crate::restrict::restricted_msg!{
70 [
71 any_type: $crate::chancell::msg::AnyChanMsg,
72 msg_mod: $crate::chancell::msg,
73 cmd_type: $crate::chancell::ChanCmd,
74 unrecognized: $crate::chancell::msg::Unrecognized,
75 body_trait: $crate::chancell::msg::Body,
76 msg_trait: $crate::chancell::ChanMsg,
77 omit_from: $($omit_from)?
78 ]
79 $(#[$meta])*
80 $v enum $name { $($tt)*}
81 }
82 };
83 {
84 [
85 any_type: $any_msg:ty,
86 msg_mod: $msg_mod:path,
87 cmd_type: $cmd_type:ty,
88 unrecognized: $unrec_type:ty,
89 body_trait: $body_type:ty,
90 msg_trait: $msg_trait:ty,
91 omit_from: $($omit_from:literal)?
92 ]
93 $(#[$meta:meta])*
94 $v:vis enum $name:ident {
95 $(
96 $(#[$case_meta:meta])*
97 $([feature=$feat:literal])?
98 $case:ident
99 ),*
100 $(, _ =>
101 $(#[$unrec_meta:meta])*
102 $unrecognized:ident )?
103 $(,)?
104 }
105 } => {
106 $crate::restrict::paste::paste!{
107 $(#[$meta])*
108 $v enum $name {
109 $(
110 $(#[$case_meta])*
111 $( #[cfg(feature=$feat)] )?
112 $case($msg_mod :: $case),
113 )*
114 $(
115 $(#[$unrec_meta])*
116 $unrecognized($unrec_type)
117 )?
118 }
119
120 impl $msg_trait for $name {
121 fn cmd(&self) -> $cmd_type {
122 match self {
123 $(
124 $( #[cfg(feature=$feat)] )?
125 Self::$case(_) => $cmd_type:: [<$case:snake:upper>] ,
126 )*
127 $(
128 Self::$unrecognized(u) => u.cmd(),
129 )?
130 }
131 }
132
133 fn encode_onto<W:>(self, w: &mut W) -> $crate::restrict::tor_bytes::EncodeResult<()>
134 where
135 W: $crate::restrict::tor_bytes::Writer + ?Sized
136 {
137 match self {
138 $(
139 $( #[cfg(feature=$feat)] )?
140 Self::$case(m) => $body_type::encode_onto(m, w),
141 )*
142 $(
143 Self::$unrecognized(u) => $body_type::encode_onto(u, w),
144 )?
145 }
146 }
147
148 fn decode_from_reader(cmd: $cmd_type, r: &mut $crate::restrict::tor_bytes::Reader<'_>) -> $crate::restrict::tor_bytes::Result<Self> {
149 Ok(match cmd {
150 $(
151 $( #[cfg(feature=$feat)] )?
152 $cmd_type:: [<$case:snake:upper>] => Self::$case( <$msg_mod :: $case as $body_type> :: decode_from_reader(r)? ),
153 )*
154 $(
155 _ => Self::$unrecognized($unrec_type::decode_with_cmd(cmd, r)?),
156 )?
157 #[allow(unreachable_patterns)] _ => return Err($crate::restrict::tor_bytes::Error::InvalidMessage(
159 format!("Unexpected command {} in {}", cmd, stringify!($name)).into()
160 )),
161 })
162 }
163 }
164
165 #[allow(unexpected_cfgs)]
166 const _: () = {
167 $(
168 #[cfg(feature = $omit_from)]
169 )?
170 impl From<$name> for $any_msg {
171 fn from(msg: $name) -> $any_msg {
172 match msg {
173 $(
174 $( #[cfg(feature=$feat)] )?
175 $name::$case(b) => Self::$case(b),
176 )*
177 $(
178 $name::$unrecognized(u) => $any_msg::Unrecognized(u),
179 )?
180 }
181 }
182 }
183 };
184
185 #[allow(unexpected_cfgs)]
186 const _: () = {
187 $(
188 #[cfg(feature = $omit_from)]
189 )?
190 impl TryFrom<$any_msg> for $name {
191 type Error = $any_msg;
192 fn try_from(msg: $any_msg) -> std::result::Result<$name, $any_msg> {
193 Ok(match msg {
194 $(
195 $( #[cfg(feature=$feat)] )?
196 $any_msg::$case(b) => $name::$case(b),
197 )*
198 $(
199 $any_msg::Unrecognized(u) => Self::$unrecognized(u),
200 )?
201 #[allow(unreachable_patterns)]
202 other => return Err(other),
203 })
204 }
205 }
206 };
207
208 $(
209 $( #[cfg(feature=$feat)] )?
210 impl From<$msg_mod :: $case> for $name {
211 fn from(m: $msg_mod::$case) -> $name {
212 $name :: $case(m)
213 }
214 }
215 )*
216 $(
217 impl From<$unrec_type> for $name {
218 fn from (u: $unrec_type) -> $name {
219 $name::$unrecognized(u)
220 }
221 }
222 )?
223 }
224 }
225}
226
227pub use restricted_msg;
228
229#[cfg(test)]
230mod test {
231 use super::*;
232 restricted_msg! {
237 enum StrictOpenStreamMsg : RelayMsg {
238 Data,
239 Sendme,
240 End,
241 }
242 }
243
244 restricted_msg! {
246 enum CircuitBuildReply : ChanMsg {
247 Created,
248 Created2,
249 CreatedFast,
250 Destroy,
251 _ => Unrecognized,
252 }
253 }
254
255 restricted_msg! {
257 enum StrictCircuitBuildReply : ChanMsg {
258 Created,
259 Created2,
260 CreatedFast,
261 Destroy,
262 }
263 }
264}