Skip to main content

tightbeam/macros/
server.rs

1#![allow(clippy::type_complexity)]
2
3#[cfg(not(feature = "std"))]
4extern crate alloc;
5
6use core::{future::Future, pin::Pin};
7
8#[cfg(not(feature = "std"))]
9use alloc::{boxed::Box, sync::Arc};
10#[cfg(feature = "std")]
11use std::sync::Arc;
12
13use crate::Frame;
14
15pub type HandlerFuture = Pin<Box<dyn Future<Output = Result<Option<Frame>, crate::TightBeamError>> + Send>>;
16pub type SharedHandler = Arc<dyn Fn(Frame) -> HandlerFuture + Send + Sync>;
17
18pub fn into_shared_handler<F, Fut>(handler: F) -> SharedHandler
19where
20	F: Fn(Frame) -> Fut + Send + Sync + Clone + 'static,
21	Fut: Future<Output = Result<Option<Frame>, crate::TightBeamError>> + Send + 'static,
22{
23	let handler = Arc::new(handler);
24	Arc::new(move |frame: Frame| -> HandlerFuture {
25		let handler = ::std::sync::Arc::clone(&handler);
26		Box::pin(async move { handler(frame).await })
27	})
28}
29
30#[cfg(feature = "tokio")]
31#[macro_export]
32macro_rules! __tightbeam_server_protocol_handle {
33	($protocol:path, $listener:expr, $handler:expr) => {{
34		let __listener = $listener;
35		$crate::macros::server::server_runtime::rt::spawn(async move {
36			let __error_tx = $crate::macros::server::server_runtime::rt::empty_error_channel();
37			let __ok_tx = $crate::macros::server::server_runtime::rt::empty_ok_channel();
38			$crate::server!(@async_loop $protocol, __listener, $handler, __error_tx, __ok_tx,)
39		})
40	}};
41
42	($protocol:path, $listener:expr, assertions: $assertions:expr, ($param1:ident, $param2:ident, $handler_body:expr)) => {{
43		#[allow(unused_imports)]
44		use $crate::trace::TraceCollector;
45
46		let __listener = $listener;
47		let __assertions = $assertions;
48		$crate::macros::server::server_runtime::rt::spawn(async move {
49			let __error_tx = $crate::macros::server::server_runtime::rt::empty_error_channel();
50			let __ok_tx = $crate::macros::server::server_runtime::rt::empty_ok_channel();
51			$crate::server!(@async_loop_assertions $protocol, __listener, __assertions, ($param1, $param2, $handler_body), __error_tx, __ok_tx,)
52		})
53	}};
54}
55
56#[cfg(all(not(feature = "tokio"), feature = "std"))]
57#[macro_export]
58macro_rules! __tightbeam_server_protocol_handle {
59	($protocol:path, $listener:expr, $handler:expr) => {{
60		let __listener = $listener;
61		std::thread::spawn(move || {
62			$crate::server!(@sync_loop $protocol, __listener, $handler,)
63		})
64	}};
65}
66
67#[cfg(not(any(feature = "tokio", feature = "std")))]
68#[macro_export]
69macro_rules! __tightbeam_server_protocol_handle {
70	($protocol:path, $listener:expr, $handler:expr) => {
71		compile_error!("server!(protocol …) requires tightbeam to be built with either the `tokio` or `std` feature");
72	};
73}
74
75#[cfg(feature = "tokio")]
76#[macro_export]
77macro_rules! __tightbeam_server_protocol_bind_handle {
78	($protocol:path, $addr:expr, $handler:expr) => {{
79		let (listener, _) = <$protocol as $crate::transport::Protocol>::bind($addr).await?;
80		let __server = <$protocol>::from(listener);
81		$crate::macros::server::server_runtime::rt::spawn(async move {
82			let __error_tx = $crate::macros::server::server_runtime::rt::empty_error_channel();
83			let __ok_tx = $crate::macros::server::server_runtime::rt::empty_ok_channel();
84			$crate::server!(@async_loop $protocol, __server, $handler, __error_tx, __ok_tx,)
85		})
86	}};
87}
88
89#[cfg(all(not(feature = "tokio"), feature = "std"))]
90#[macro_export]
91macro_rules! __tightbeam_server_protocol_bind_handle {
92	($protocol:path, $addr:expr, $handler:expr) => {{
93		let (listener, _) = <$protocol as $crate::transport::Protocol>::bind($addr)?;
94		let __server = <$protocol>::from(listener);
95		std::thread::spawn(move || {
96			$crate::server!(@sync_loop $protocol, __server, $handler,)
97		})
98	}};
99}
100
101#[cfg(not(any(feature = "tokio", feature = "std")))]
102#[macro_export]
103macro_rules! __tightbeam_server_protocol_bind_handle {
104	($protocol:path, $addr:expr, $handler:expr) => {
105		compile_error!(
106			"server!(protocol …) with `bind` requires tightbeam to be built with either the `tokio` or `std` feature"
107		);
108	};
109}
110
111#[cfg(feature = "tokio")]
112#[macro_export]
113macro_rules! __tightbeam_server_protocol_policies_handle {
114	($protocol:path, $listener:expr, [$($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)?], $handler:expr) => {{
115		let __listener = $listener;
116		$crate::macros::server::server_runtime::rt::spawn(async move {
117			let __error_tx = $crate::macros::server::server_runtime::rt::empty_error_channel();
118			let __ok_tx = $crate::macros::server::server_runtime::rt::empty_ok_channel();
119			$crate::server!(@async_loop $protocol, __listener, $handler, __error_tx, __ok_tx, $($policy_name: [ $( $policy_expr ),* ]),*)
120		})
121	}};
122}
123
124#[cfg(all(not(feature = "tokio"), feature = "std"))]
125#[macro_export]
126macro_rules! __tightbeam_server_protocol_policies_handle {
127	($protocol:path, $listener:expr, [$($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)?], $handler:expr) => {{
128		let __listener = $listener;
129		std::thread::spawn(move || {
130			$crate::server!(@sync_loop $protocol, __listener, $handler, $($policy_name: [ $( $policy_expr ),* ]),*)
131		})
132	}};
133}
134
135#[cfg(not(any(feature = "tokio", feature = "std")))]
136#[macro_export]
137macro_rules! __tightbeam_server_protocol_policies_handle {
138	($protocol:path, $listener:expr, [$($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)?], $handler:expr) => {
139		compile_error!(
140			"server!(protocol …, policies: …) requires tightbeam to be built with either the `tokio` or `std` feature"
141		);
142	};
143}
144
145#[cfg(feature = "tokio")]
146#[macro_export]
147macro_rules! __tightbeam_server_protocol_policies_assertions_handle {
148	($protocol:path, $listener:expr, [$($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)?], $assertions:expr, ($param1:ident, $param2:ident, $handler_body:expr)) => {{
149		#[allow(unused_imports)]
150		use $crate::trace::TraceCollector;
151
152		let __listener = $listener;
153		let __assertions = $assertions;
154		$crate::macros::server::server_runtime::rt::spawn(async move {
155			let __error_tx = $crate::macros::server::server_runtime::rt::empty_error_channel();
156			let __ok_tx = $crate::macros::server::server_runtime::rt::empty_ok_channel();
157			$crate::server!(@async_loop_assertions $protocol, __listener, __assertions, ($param1, $param2, $handler_body), __error_tx, __ok_tx, $($policy_name: [ $( $policy_expr ),* ]),*)
158		})
159	}};
160}
161
162#[cfg(all(not(feature = "tokio"), feature = "std"))]
163#[macro_export]
164macro_rules! __tightbeam_server_protocol_policies_assertions_handle {
165	($protocol:path, $listener:expr, [$($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)?], $assertions:expr, ($param1:ident, $param2:ident, $handler_body:expr)) => {{
166		compile_error!("server!(protocol …, policies: …, assertions: …) requires the `tokio` feature");
167	}};
168}
169
170#[cfg(not(any(feature = "tokio", feature = "std")))]
171#[macro_export]
172macro_rules! __tightbeam_server_protocol_policies_assertions_handle {
173	($protocol:path, $listener:expr, [$($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)?], $assertions:expr, ($param1:ident, $param2:ident, $handler_body:expr)) => {{
174		compile_error!(
175			"server!(protocol …, policies: …, assertions: …) requires tightbeam to be built with either the `tokio` or `std` feature"
176		);
177	}};
178}
179
180#[cfg(feature = "tokio")]
181#[macro_export]
182macro_rules! __tightbeam_server_protocol_channels_handle {
183	($protocol:path, $listener:expr, $error_tx:expr, $ok_tx:expr, $handler:expr) => {{
184		let __listener = $listener;
185		$crate::macros::server::server_runtime::rt::spawn(async move {
186			let __error_tx = Some($error_tx);
187			let __ok_tx = Some($ok_tx);
188			$crate::server!(@async_loop $protocol, __listener, $handler, __error_tx, __ok_tx,)
189		})
190	}};
191}
192
193#[cfg(all(not(feature = "tokio"), feature = "std"))]
194#[macro_export]
195macro_rules! __tightbeam_server_protocol_channels_handle {
196	($protocol:path, $listener:expr, $error_tx:expr, $ok_tx:expr, $handler:expr) => {{
197		let __listener = $listener;
198		let _ = ($error_tx, $ok_tx);
199		std::thread::spawn(move || {
200			$crate::server!(@sync_loop $protocol, __listener, $handler,)
201		})
202	}};
203}
204
205#[cfg(not(any(feature = "tokio", feature = "std")))]
206#[macro_export]
207macro_rules! __tightbeam_server_protocol_channels_handle {
208	($protocol:path, $listener:expr, $error_tx:expr, $ok_tx:expr, $handler:expr) => {
209		let _ = ($error_tx, $ok_tx);
210		compile_error!(
211			"server!(protocol …, channels: …) requires tightbeam to be built with either the `tokio` or `std` feature"
212		);
213	};
214}
215
216#[cfg(feature = "tokio")]
217#[macro_export]
218macro_rules! __tightbeam_server_protocol_channels_policies_handle {
219	($protocol:path, $listener:expr, $error_tx:expr, $ok_tx:expr, [$($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)?], $handler:expr) => {{
220		let __listener = $listener;
221		$crate::macros::server::server_runtime::rt::spawn(async move {
222			let __error_tx = Some($error_tx);
223			let __ok_tx = Some($ok_tx);
224			$crate::server!(@async_loop $protocol, __listener, $handler, __error_tx, __ok_tx, $($policy_name: [ $( $policy_expr ),* ]),*)
225		})
226	}};
227}
228
229#[cfg(all(not(feature = "tokio"), feature = "std"))]
230#[macro_export]
231macro_rules! __tightbeam_server_protocol_channels_policies_handle {
232	($protocol:path, $listener:expr, $error_tx:expr, $ok_tx:expr, [$($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)?], $handler:expr) => {{
233		let __listener = $listener;
234		let _ = ($error_tx, $ok_tx);
235		std::thread::spawn(move || {
236			$crate::server!(@sync_loop $protocol, __listener, $handler, $($policy_name: [ $( $policy_expr ),* ]),*)
237		})
238	}};
239}
240
241#[cfg(not(any(feature = "tokio", feature = "std")))]
242#[macro_export]
243macro_rules! __tightbeam_server_protocol_channels_policies_handle {
244	($protocol:path, $listener:expr, $error_tx:expr, $ok_tx:expr, [$($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)?], $handler:expr) => {
245		let _ = ($error_tx, $ok_tx);
246		compile_error!(
247			"server!(protocol …, channels: …) requires tightbeam to be built with either the `tokio` or `std` feature"
248		);
249	};
250}
251
252#[cfg(feature = "tokio")]
253#[macro_export]
254macro_rules! __tightbeam_server_protocol_bind_policies_handle {
255	($protocol:path, $addr:expr, [$($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)?], $handler:expr) => {{
256		let (listener, _) = <$protocol as $crate::transport::Protocol>::bind($addr).await?;
257		let __server = <$protocol>::from(listener);
258		$crate::macros::server::server_runtime::rt::spawn(async move {
259			let __error_tx = $crate::macros::server::server_runtime::rt::empty_error_channel();
260			let __ok_tx = $crate::macros::server::server_runtime::rt::empty_ok_channel();
261			$crate::server!(@async_loop $protocol, __server, $handler, __error_tx, __ok_tx, $($policy_name: [ $( $policy_expr ),* ]),*)
262		})
263	}};
264}
265
266#[cfg(all(not(feature = "tokio"), feature = "std"))]
267#[macro_export]
268macro_rules! __tightbeam_server_protocol_bind_policies_handle {
269	($protocol:path, $addr:expr, [$($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)?], $handler:expr) => {{
270		let (listener, _) = <$protocol as $crate::transport::Protocol>::bind($addr)?;
271		let __server = <$protocol>::from(listener);
272		std::thread::spawn(move || {
273			$crate::server!(@sync_loop $protocol, __server, $handler, $($policy_name: [ $( $policy_expr ),* ]),*)
274		})
275	}};
276}
277
278#[cfg(not(any(feature = "tokio", feature = "std")))]
279#[macro_export]
280macro_rules! __tightbeam_server_protocol_bind_policies_handle {
281	($protocol:path, $addr:expr, [$($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)?], $handler:expr) => {
282		compile_error!("server!(protocol …, policies: …) with `bind` requires tightbeam to be built with either the `tokio` or `std` feature");
283	};
284}
285
286/// Server-specific runtime extensions
287///
288/// Re-exports unified runtime and adds server-specific channel helpers.
289#[cfg(any(feature = "tokio", feature = "std"))]
290pub mod server_runtime {
291	/// Runtime primitives (re-exported from unified runtime)
292	pub mod rt {
293		pub use crate::runtime::rt::*;
294
295		use crate::transport::error::TransportError;
296
297		/// Error notification channel sender type
298		pub type ErrorSender = crate::runtime::rt::Sender<TransportError>;
299
300		/// Success notification channel sender type
301		pub type OkSender = crate::runtime::rt::Sender<()>;
302
303		/// Returns None for optional error channel
304		#[allow(dead_code)]
305		pub fn empty_error_channel() -> Option<ErrorSender> {
306			None
307		}
308
309		/// Returns None for optional success channel
310		#[allow(dead_code)]
311		pub fn empty_ok_channel() -> Option<OkSender> {
312			None
313		}
314	}
315}
316
317#[macro_export]
318macro_rules! server {
319	(@apply_policy $transport:ident, $policy_name:ident, [ $( $policy_expr:expr ),* $(,)? ]) => {{
320		$(
321			$transport = $crate::server!(@apply_one_policy $transport, $policy_name, $policy_expr);
322		)*
323	}};
324
325	// Generic fallback
326	(@apply_one_policy $transport:ident, $other:ident, $policy_expr:expr) => {{
327		$transport.$other($policy_expr)
328	}};
329
330	(@sync_loop_body $protocol:path, $listener:ident, $handler:ident, $($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)?) => {{
331		loop {
332			match $listener.accept() {
333				Ok((mut __transport, _addr)) => {
334					$(
335						$(
336							__transport = $crate::server!(@apply_one_policy __transport, $policy_name, $policy_expr);
337						)*
338					)*
339					let __handler_clone = ::std::sync::Arc::clone(&$handler);
340					#[allow(unused_imports)]
341					use $crate::transport::MessageCollector;
342					$crate::macros::server::server_runtime::rt::spawn(move || {
343						let mut __transport = __transport;
344						loop {
345							// Read message
346							let (frame, status) = match $crate::macros::server::server_runtime::rt::block_on(__transport.collect_message()) {
347								Ok(result) => result,
348								Err(err) => {
349									break;
350								}
351							};
352
353							// Process message asynchronously
354							let response = if status == $crate::policy::TransitStatus::Accepted {
355								$crate::macros::server::server_runtime::rt::block_on((__handler_clone)(frame))
356							} else {
357								None
358							};
359
360							// Send response
361							match $crate::macros::server::server_runtime::rt::block_on(__transport.send_response(status, response)) {
362								Ok(()) => continue,
363								Err(err) => {
364									break;
365								}
366							}
367						}
368					});
369				}
370				Err(_err) => {
371					break;
372				}
373			}
374		}
375	}};
376
377	(@async_loop_body $protocol:path, $listener:ident, $handler:ident, $error_tx:ident, $ok_tx:ident, $($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)?) => {{
378		loop {
379			match $listener.accept().await {
380				Ok((mut __transport, _addr)) => {
381					$(
382						$(
383							__transport = $crate::server!(@apply_one_policy __transport, $policy_name, $policy_expr);
384						)*
385					)*
386					let __handler_clone = ::std::sync::Arc::clone(&$handler);
387					let mut __error_channel = $error_tx.clone();
388					let mut __ok_channel = $ok_tx.clone();
389					use $crate::transport::MessageCollector;
390					$crate::macros::server::server_runtime::rt::spawn(async move {
391						let mut __transport = __transport;
392						loop {
393							// Read message
394							let (frame, status) = match __transport.collect_message().await {
395								Ok(result) => result,
396								Err(err) => {
397									if let Some(tx) = __error_channel.as_mut() {
398										let _ = tx.send(err).await;
399									}
400									break;
401								}
402							};
403
404							// Process message asynchronously
405							// Unwrap Arc<Frame> to Frame for handler (clone only if Arc has multiple owners)
406							let frame_owned = std::sync::Arc::try_unwrap(frame)
407								.unwrap_or_else(|arc| (*arc).clone());
408							let response = if status == $crate::policy::TransitStatus::Accepted {
409								match (__handler_clone)(frame_owned).await {
410									Ok(opt) => opt,
411									Err(_err) => {
412										None
413									}
414								}
415							} else {
416								None
417							};
418
419							// Send response
420							match __transport.send_response(status, response).await {
421								Ok(()) => {
422									if let Some(tx) = __ok_channel.as_mut() {
423										let _ = tx.send(()).await;
424									}
425								}
426								Err(err) => {
427									if let Some(tx) = __error_channel.as_mut() {
428										let _ = tx.send(err).await;
429									}
430									break;
431								}
432							}
433						}
434					});
435				}
436				Err(e) => {
437					if let Some(tx) = $error_tx.as_mut() {
438						let _ = tx.send(e.into()).await;
439					}
440
441					break;
442				}
443			}
444		}
445	}};
446
447	(@sync_loop $protocol:path, $listener:expr, $handler:expr, $($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)?) => {{
448		let mut __listener = $listener;
449		let __handler = $crate::macros::server::into_shared_handler($handler);
450
451		$crate::server!(@sync_loop_body $protocol, __listener, __handler, $($policy_name: [ $( $policy_expr ),* ]),*);
452	}};
453
454	(@async_loop_assertions $protocol:path, $listener:expr, $assertions:expr, ($param1:ident, $param2:ident, $handler_body:expr), $error_tx:expr, $ok_tx:expr, $($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)?) => {{
455		#[allow(unused_imports)]
456		use $crate::trace::TraceCollector;
457
458		let __assertions = ::std::sync::Arc::new($assertions);
459		let __handler_with_trace = {
460			let __assertions = ::std::sync::Arc::clone(&__assertions);
461			move |$param1: $crate::Frame| {
462				let $param2: TraceCollector = __assertions.as_ref().share();
463				$handler_body
464			}
465		};
466
467		$crate::server!(@async_loop $protocol, $listener, __handler_with_trace, $error_tx, $ok_tx, $($policy_name: [ $( $policy_expr ),* ]),*);
468	}};
469
470	(@async_loop $protocol:path, $listener:expr, $handler:expr, $error_tx:expr, $ok_tx:expr, $($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)?) => {{
471		let mut __listener = $listener;
472		let __handler = $crate::macros::server::into_shared_handler($handler);
473		let mut __error_tx = $error_tx;
474		let mut __ok_tx = $ok_tx;
475
476		$crate::server!(@async_loop_body $protocol, __listener, __handler, __error_tx, __ok_tx, $($policy_name: [ $( $policy_expr ),* ]),*);
477	}};
478
479	($protocol:path: $listener:expr, handle: $handler:expr) => {{
480		#[cfg(feature = "std")]
481		{
482			let __listener = $listener;
483			$crate::server!(@sync_loop $protocol, __listener, $handler,)
484		}
485	}};
486
487	($protocol:path: bind $addr:expr, handle: $handler:expr) => {{
488		#[cfg(feature = "std")]
489		{
490			let (listener, _) = <$protocol as $crate::transport::Protocol>::bind($addr)?;
491			let __server = <$protocol>::from(listener);
492			$crate::server!(@sync_loop $protocol, __server, $handler,)
493		}
494	}};
495
496	($protocol:path: $listener:expr, policies: { $($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)? }, handle: $handler:expr) => {{
497		#[cfg(feature = "std")]
498		{
499			let __listener = $listener;
500			$crate::server!(@sync_loop $protocol, __listener, $handler, $($policy_name: [ $( $policy_expr ),* ]),*);
501		}
502	}};
503
504	($protocol:path: bind $addr:expr, policies: { $($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)? }, handle: $handler:expr) => {{
505		#[cfg(feature = "std")]
506		{
507			let (listener, _) = <$protocol as $crate::transport::Protocol>::bind($addr)?;
508			let __server = <$protocol>::from(listener);
509			$crate::server!(@sync_loop $protocol, __server, $handler, $($policy_name: [ $( $policy_expr ),* ]),*);
510		}
511	}};
512
513	(protocol $protocol:path: $listener:expr, handle: $handler:expr) => {{
514		$crate::__tightbeam_server_protocol_handle!($protocol, $listener, $handler)
515	}};
516
517	(protocol $protocol:path: $listener:expr, assertions: $assertions:expr, handle: move |$param1:ident, $param2:ident| $handler_body:expr) => {{
518		$crate::__tightbeam_server_protocol_handle!($protocol, $listener, assertions: $assertions, ($param1, $param2, $handler_body))
519	}};
520
521	(protocol $protocol:path: $listener:expr, assertions: $assertions:expr, handle: |$param1:ident, $param2:ident| $handler_body:expr) => {{
522		$crate::__tightbeam_server_protocol_handle!($protocol, $listener, assertions: $assertions, ($param1, $param2, $handler_body))
523	}};
524
525	(protocol $protocol:path: bind $addr:expr, handle: $handler:expr) => {{
526		$crate::__tightbeam_server_protocol_bind_handle!($protocol, $addr, $handler)
527	}};
528
529	(protocol $protocol:path: $listener:expr, policies: { $($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)? }, handle: $handler:expr) => {{
530		$crate::__tightbeam_server_protocol_policies_handle!($protocol, $listener, [ $($policy_name: [ $( $policy_expr ),* ]),* ], $handler)
531	}};
532
533	(protocol $protocol:path: $listener:expr, policies: { $($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)? }, assertions: $assertions:expr, handle: move |$param1:ident, $param2:ident| $handler_body:expr) => {{
534		$crate::__tightbeam_server_protocol_policies_assertions_handle!(
535			$protocol,
536			$listener,
537			[ $($policy_name: [ $( $policy_expr ),* ]),* ],
538			$assertions,
539			($param1, $param2, $handler_body)
540		)
541	}};
542
543	(protocol $protocol:path: $listener:expr, policies: { $($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)? }, assertions: $assertions:expr, handle: |$param1:ident, $param2:ident| $handler_body:expr) => {{
544		$crate::__tightbeam_server_protocol_policies_assertions_handle!(
545			$protocol,
546			$listener,
547			[ $($policy_name: [ $( $policy_expr ),* ]),* ],
548			$assertions,
549			($param1, $param2, $handler_body)
550		)
551	}};
552
553	(protocol $protocol:path: $listener:expr, assertions: $assertions:expr, policies: { $($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)? }, handle: move |$param1:ident, $param2:ident| $handler_body:expr) => {{
554		$crate::__tightbeam_server_protocol_policies_assertions_handle!(
555			$protocol,
556			$listener,
557			[ $($policy_name: [ $( $policy_expr ),* ]),* ],
558			$assertions,
559			($param1, $param2, $handler_body)
560		)
561	}};
562
563	(protocol $protocol:path: $listener:expr, assertions: $assertions:expr, policies: { $($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)? }, handle: |$param1:ident, $param2:ident| $handler_body:expr) => {{
564		$crate::__tightbeam_server_protocol_policies_assertions_handle!(
565			$protocol,
566			$listener,
567			[ $($policy_name: [ $( $policy_expr ),* ]),* ],
568			$assertions,
569			($param1, $param2, $handler_body)
570		)
571	}};
572
573	(protocol $protocol:path: $listener:expr, channels: { error: $error_tx:expr, ok: $ok_tx:expr }, handle: $handler:expr) => {{
574		$crate::__tightbeam_server_protocol_channels_handle!($protocol, $listener, $error_tx, $ok_tx, $handler)
575	}};
576
577	(protocol $protocol:path: $listener:expr, channels: { error: $error_tx:expr, ok: $ok_tx:expr }, policies: { $($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)? }, handle: $handler:expr) => {{
578		$crate::__tightbeam_server_protocol_channels_policies_handle!($protocol, $listener, $error_tx, $ok_tx, [ $($policy_name: [ $( $policy_expr ),* ]),* ], $handler)
579	}};
580
581	(protocol $protocol:path: bind $addr:expr, policies: { $($policy_name:ident: [ $( $policy_expr:expr ),* $(,)? ]),* $(,)? }, handle: $handler:expr) => {{
582		$crate::__tightbeam_server_protocol_bind_policies_handle!($protocol, $addr, [ $($policy_name: [ $( $policy_expr ),* ]),* ], $handler)
583	}};
584
585	(async $($rest:tt)*) => {
586		$crate::server!(protocol $($rest)*)
587	};
588}