async_coap/send_desc/
mod.rs

1// Copyright 2019 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15
16//! # Send Descriptors
17//!
18//! *Send Descriptors* are types that implement [`SendDesc`] that can be passed to the `send*`
19//! methods of [`LocalEndpoint`] and [`RemoteEndpoint`]. They define almost every aspect of how
20//! a message transaction is handled.
21//!
22//! Typical usage of this crate does not require writing implementing [`SendDesc`] by hand,
23//! although you could certainly do so if needed.
24//! Instead, `SyncDesc` instances are easily constructed using *combinators*.
25//!
26//! ## Example
27//!
28//! Here we create a `SendDesc` instance that just sends a GET request and waits for a response:
29//!
30//! ```
31//! # #![feature(async_await)]
32//! # use std::sync::Arc;
33//! # use futures::{prelude::*,executor::LocalPool,task::LocalSpawnExt};
34//! # use async_coap::prelude::*;
35//! # use async_coap::datagram::{DatagramLocalEndpoint, AllowStdUdpSocket, LoopbackSocket};
36//! # use async_coap::null::NullLocalEndpoint;
37//! # let socket = AllowStdUdpSocket::bind("[::]:0").expect("UDP bind failed");
38//! # let local_endpoint = Arc::new(DatagramLocalEndpoint::new(socket));
39//! # let mut pool = LocalPool::new();
40//! # pool.spawner().spawn_local(local_endpoint.clone().receive_loop_arc(null_receiver!()).map(|_|unreachable!()));
41//! # let future = async move {
42//! #
43//! let mut remote_endpoint = local_endpoint
44//!     .remote_endpoint_from_uri(uri!("coap://coap.me:5683/test"))
45//!     .expect("Remote endpoint lookup failed");
46//!
47//! let future = remote_endpoint.send(CoapRequest::get());
48//!
49//! assert_eq!(future.await, Ok(()));
50//! #
51//! #
52//! # };
53//! # pool.run_until(future);
54//! ```
55//!
56//! That `SendDesc` was perhaps a little *too* simple: it doesn't even interpret the results,
57//! returning `Ok(())` for any message responding with a `2.05 Content` message!
58//!
59//! By using the combinator `.emit_successful_response()`, we can have our `SendDesc` return
60//! an owned copy of the message it received ([`OwnedImmutableMessage`](crate::message::OwnedImmutableMessage)):
61//!
62//! ```
63//! # #![feature(async_await)]
64//! # use std::sync::Arc;
65//! # use futures::{prelude::*,executor::LocalPool,task::LocalSpawnExt};
66//! # use async_coap::prelude::*;
67//! # use async_coap::datagram::{DatagramLocalEndpoint, AllowStdUdpSocket, LoopbackSocket};
68//! # let socket = AllowStdUdpSocket::bind("[::]:0").expect("UDP bind failed");
69//! # let local_endpoint = Arc::new(DatagramLocalEndpoint::new(socket));
70//! # let mut pool = LocalPool::new();
71//! # pool.spawner().spawn_local(local_endpoint.clone().receive_loop_arc(null_receiver!()).map(|_|unreachable!()));
72//! # let future = async move {
73//! #    use async_coap::message::OwnedImmutableMessage;
74//! #    let mut remote_endpoint = local_endpoint
75//! #        .remote_endpoint_from_uri(uri!("coap://coap.me:5683/test"))
76//! #        .expect("Remote endpoint lookup failed");
77//! #
78//! #
79//! let send_desc = CoapRequest::get().emit_successful_response();
80//!
81//! let future = remote_endpoint.send(send_desc);
82//!
83//! let message = future.await.expect("Request failed");
84//!
85//! println!("Got reply: {:?}", message);
86//! #
87//! #
88//! # };
89//! # pool.run_until(future);
90//! ```
91//!
92//! What if we wanted the response in JSON? What if it was really large and we
93//! knew we would need to do a block2 transfer? We can do that easily:
94//!
95//! ```ignore
96//! let send_desc = CoapRequest::get()
97//!     .accept(ContentFormat::APPLICATION_JSON)
98//!     .block2(None)
99//!     .emit_successful_collected_response();
100//!
101//! // Here we are specifying that we want to send the request to a specific
102//! // path on the remote endpoint, `/large` in this case.
103//! let future = remote_endpoint.send_to(rel_ref!("/large"), send_desc);
104//!
105//! let message = future.await.expect("Request failed");
106//!
107//! println!("Got reply: {:?}", message);
108//! ```
109//!
110//! But if this is a large amount of data, we won't get any indication about the transfer
111//! until it is done. What if we wanted to add some printouts about the status?
112//!
113//! ```ignore
114//! let send_desc = CoapRequest::get()
115//!     .accept(ContentFormat::APPLICATION_JSON)
116//!     .block2(None)
117//!     .emit_successful_collected_response()
118//!     .inspect(|context| {
119//!         let addr = context.remote_address();
120//!         let msg = context.message();
121//!
122//!         // Print out each individual block message received.
123//!         println!("Got {:?} from {}", msg, addr);
124//!     });
125//!
126//! let future = remote_endpoint.send_to(rel_ref!("/large"), send_desc);
127//!
128//! let message = future.await.expect("Request failed");
129//!
130//! println!("Got reply: {:?}", message);
131//! ```
132//!
133//! There are [many more combinators][SendDescExt] for doing all sorts of things, such as
134//! adding additional options and [block2 message aggregation](SendDescUnicast::block2).
135
136use super::*;
137
138mod request;
139pub use request::*;
140
141mod observe;
142pub use observe::*;
143
144mod unicast_block2;
145pub use unicast_block2::*;
146
147mod handler;
148pub use handler::*;
149
150mod inspect;
151pub use inspect::*;
152
153mod payload;
154pub use payload::*;
155
156mod ping;
157pub use ping::Ping;
158
159mod add_option;
160pub use add_option::*;
161
162mod nonconfirmable;
163pub use nonconfirmable::*;
164
165mod multicast;
166pub use multicast::*;
167
168mod emit;
169pub use emit::*;
170
171mod include_socket_addr;
172pub use include_socket_addr::*;
173
174mod uri_host_path;
175pub use uri_host_path::UriHostPath;
176
177use std::iter::{once, Once};
178use std::marker::PhantomData;
179use std::ops::Bound;
180use std::time::Duration;
181
182/// # Send Descriptor Trait
183///
184/// Types implementing this trait can be passed to the `send*` methods of [`LocalEndpoint`]
185/// and [`RemoteEndpoint`], and can define almost every aspect of how a message transaction
186/// is handled.
187///
188/// See the [module level documentation](index.html) for more information on typical usage
189/// patterns.
190///
191/// ## Internals
192///
193/// There are several methods in this trait, but three of them are critical:
194///
195/// * [`write_options`](SendDesc::write_options)\: Defines which options are going to be
196///   included in the outbound message.
197/// * [`write_payload`](SendDesc::write_payload)\: Defines the contents of the payload for the
198///   outbound message.
199/// * [`handler`](SendDesc::handler)\: Handles inbound reply messages, as well as error conditions.
200///
201pub trait SendDesc<IC, R = (), TP = StandardCoapConstants>: Send
202where
203    IC: InboundContext,
204    R: Send,
205    TP: TransParams,
206{
207    /// **Experimental**: Gets custom transmission parameters.
208    fn trans_params(&self) -> Option<TP> {
209        None
210    }
211
212    /// **Experimental**: Used for determining if the given option seen in the reply message
213    /// is supported or not.
214    ///
215    /// Response messages with any options that cause this
216    /// method to return false will be rejected.
217    ///
218    fn supports_option(&self, option: OptionNumber) -> bool {
219        !option.is_critical()
220    }
221
222    /// Calculates the duration of the delay to wait before sending the next retransmission.
223    ///
224    /// If `None` is returned, then no further retransmissions will be attempted.
225    fn delay_to_retransmit(&self, retransmits_sent: u32) -> Option<Duration> {
226        if retransmits_sent > TP::COAP_MAX_RETRANSMIT {
227            return None;
228        }
229
230        let ret = (TP::COAP_ACK_TIMEOUT.as_millis() as u64) << retransmits_sent as u64;
231
232        const JDIV: u64 = 512u64;
233        let rmod: u64 = (JDIV as f32 * (TP::COAP_ACK_RANDOM_FACTOR - 1.0)) as u64;
234        let jmul = JDIV + rand::random::<u64>() % rmod;
235
236        Some(Duration::from_millis(ret * jmul / JDIV))
237    }
238
239    /// The delay to wait between when we have received a successful response and when
240    /// we should send out another request.
241    ///
242    /// The new request will have a new msg_id, but
243    /// the same token. The retransmission counter will be reset to zero.
244    ///
245    /// This mechanism is currently used exclusively for CoAP observing.
246    ///
247    /// The default return value is `None`, indicating that there are to be no message
248    /// restarts.
249    fn delay_to_restart(&self) -> Option<Duration> {
250        None
251    }
252
253    /// The maximum time to wait for an asynchronous response after having received an ACK.
254    fn max_rtt(&self) -> Duration {
255        TP::COAP_MAX_RTT
256    }
257
258    /// the maximum time from the first transmission of a Confirmable message to the time when
259    /// the sender gives up on receiving an acknowledgement or reset.
260    fn transmit_wait_duration(&self) -> Duration {
261        TP::COAP_MAX_TRANSMIT_WAIT
262    }
263
264    /// Defines which options are going to be included in the outbound message.
265    ///
266    /// Writes all options in the given range to `msg`.
267    fn write_options(
268        &self,
269        msg: &mut dyn OptionInsert,
270        socket_addr: &IC::SocketAddr,
271        start: Bound<OptionNumber>,
272        end: Bound<OptionNumber>,
273    ) -> Result<(), Error>;
274
275    /// Generates the outbound message by making calls into `msg`.
276    fn write_payload(
277        &self,
278        msg: &mut dyn MessageWrite,
279        socket_addr: &IC::SocketAddr,
280    ) -> Result<(), Error>;
281
282    /// Handles the response to the outbound message.
283    fn handler(&mut self, context: Result<&IC, Error>) -> Result<ResponseStatus<R>, Error>;
284}
285
286/// Marker trait for identifying that this `SendDesc` is for *unicast* requests.
287/// Also contains unicast-specific combinators, such as [`block2()`][SendDescUnicast::block2].
288pub trait SendDescUnicast {
289    /// Returns a send descriptor that will perform Block2 processing.
290    ///
291    /// Note that just adding this to your send descriptor chain alone is unlikely to do what
292    /// you want. You've got three options:
293    ///
294    /// * Add a call to [`emit_successful_collected_response`][UnicastBlock2::emit_successful_collected_response]
295    ///   immediately after the call to this method. This will cause the message to be reconstructed from the blocks
296    ///   and returned as a value from the future from `send`. You can optionally add an
297    ///   [`inspect`][SendDescExt::inspect] combinator to get some feedback as the message is being
298    ///   reconstructed from all of the individual block messages.
299    /// * Add a call to [`emit_successful_response`][SendDescExt::emit_successful_response] along
300    ///   with using `send_to_stream` instead of `send`. This will give you a `Stream` that will
301    ///   contain all of the individual block messages in the stream.
302    /// * [Add your own handler][SendDescExt::use_handler] to do whatever you need to do, returning
303    ///   `ResponseStatus::SendNext` until all of the blocks have been received. This is
304    ///   useful if you want to avoid memory allocation.
305    ///
306    /// There may be other valid combinations of combinators, depending on what you are trying
307    /// to do.
308    fn block2<IC, R, TP>(self, block2: Option<BlockInfo>) -> UnicastBlock2<Self, IC>
309    where
310        IC: InboundContext,
311        R: Send,
312        TP: TransParams,
313        Self: SendDesc<IC, R, TP> + Sized,
314    {
315        UnicastBlock2::new(self, block2)
316    }
317}
318
319/// Marker trait for identifying that this `SendDesc` is for *multicast* requests.
320/// Also contains multicast-specific extensions.
321pub trait SendDescMulticast {}
322
323/// Combinator extension trait for Send Descriptors.
324pub trait SendDescExt<IC, R, TP>: SendDesc<IC, R, TP> + Sized
325where
326    IC: InboundContext,
327    R: Send,
328    TP: TransParams,
329{
330    /// Adds zero or more instances of the option `key`, using values coming from `viter`.
331    ///
332    /// This method allows you to conditionally add options to a send descriptor. For example,
333    /// you could convert an `Option` to an iterator (using `into_iterator()`) and pass it to
334    /// this method: if the `Option` is `None` then no coap option will be added.
335    fn add_option_iter<K, I>(self, key: OptionKey<K>, viter: I) -> AddOption<Self, K, I, IC>
336    where
337        I: IntoIterator<Item = K> + Send + Clone,
338        K: Send + Clone,
339    {
340        AddOption {
341            inner: self,
342            key,
343            viter,
344            phantom: PhantomData,
345        }
346    }
347
348    /// Adds one instance of the option `key` with a value of `value`.
349    fn add_option<K>(self, key: OptionKey<K>, value: K) -> AddOption<Self, K, Once<K>, IC>
350    where
351        K: Send + Clone,
352    {
353        self.add_option_iter(key, once(value))
354    }
355
356    /// Adds an Accept option with the given `ContentFormat`.
357    fn accept(
358        self,
359        accept: ContentFormat,
360    ) -> AddOption<Self, ContentFormat, Once<ContentFormat>, IC> {
361        self.add_option(option::ACCEPT, accept)
362    }
363
364    /// Adds an Content-Format option with the given `ContentFormat`.
365    fn content_format(
366        self,
367        content_format: ContentFormat,
368    ) -> AddOption<Self, ContentFormat, Once<ContentFormat>, IC> {
369        self.add_option(option::CONTENT_FORMAT, content_format)
370    }
371
372    /// Adds a handler function to be called when a response message has been received (or when
373    /// an error has occurred).
374    fn use_handler<F, FR>(self, handler: F) -> Handler<Self, F>
375    where
376        F: FnMut(
377                Result<&dyn InboundContext<SocketAddr = IC::SocketAddr>, Error>,
378            ) -> Result<ResponseStatus<FR>, Error>
379            + Send,
380        FR: Send,
381    {
382        Handler {
383            inner: self,
384            handler,
385        }
386    }
387
388    /// Updates the send descriptor chain to emit any received message as a result, even
389    /// if that message has a message code that indicates an error.
390    fn emit_any_response(self) -> EmitAnyResponse<Self> {
391        EmitAnyResponse::new(self)
392    }
393
394    /// Updates the send descriptor chain to emit received message as a result, but only
395    /// if that message has a message code that indicates success.
396    fn emit_successful_response(self) -> EmitSuccessfulResponse<Self> {
397        EmitSuccessfulResponse::new(self)
398    }
399
400    /// Updates the send descriptor chain to emit only the message code of the received
401    /// response.
402    fn emit_msg_code(self) -> EmitMsgCode<Self> {
403        EmitMsgCode::new(self)
404    }
405
406    /// Updates the send descriptor chain to also emit the SocketAddr of the sender
407    /// of the response, resulting in tuple return type.
408    ///
409    /// This is useful for handling responses to a multicast request.
410    fn include_socket_addr(self) -> IncludeSocketAddr<Self> {
411        IncludeSocketAddr::new(self)
412    }
413
414    /// Adds an inspection closure that will be called for each received response message.
415    ///
416    /// The inspector closure will not be called if no responses are received, and it cannot
417    /// change the behavior of the send descriptor chain. If you need either of those
418    /// behaviors, see [`SendDescExt::use_handler`].
419    fn inspect<F>(self, inspect: F) -> Inspect<Self, F>
420    where
421        F: FnMut(&dyn InboundContext<SocketAddr = IC::SocketAddr>) + Send,
422    {
423        Inspect {
424            inner: self,
425            inspect,
426        }
427    }
428
429    /// Adds a closure that writes to the payload of the outbound message.
430    fn payload_writer<F>(self, writer: F) -> PayloadWriter<Self, F>
431    where
432        F: Fn(&mut dyn MessageWrite) -> Result<(), Error> + Send,
433    {
434        PayloadWriter {
435            inner: self,
436            writer,
437        }
438    }
439
440    /// Allows you to specify the URI_HOST, URI_PATH, and URI_QUERY option values
441    /// in a more convenient way than using `add_option_iter` manually.
442    fn uri_host_path<T: Into<RelRefBuf>>(
443        self,
444        host: Option<String>,
445        uri_path: T,
446    ) -> UriHostPath<Self, IC> {
447        UriHostPath {
448            inner: self,
449            host,
450            path_and_query: uri_path.into(),
451            phantom: PhantomData,
452        }
453    }
454}
455
456/// Blanket implementation of `SendDescExt` for all types implementing `SendDesc`.
457impl<T, IC, R, TP> SendDescExt<IC, R, TP> for T
458where
459    T: SendDesc<IC, R, TP>,
460    IC: InboundContext,
461    R: Send,
462    TP: TransParams,
463{
464}
465
466/// Helper macro that assists with writing correct implementations of [`SendDesc::write_options`].
467///
468/// ## Example
469///
470/// ```
471/// # use async_coap::uri::RelRefBuf;
472/// # use std::marker::PhantomData;
473/// # use async_coap::send_desc::SendDesc;
474/// # use async_coap::prelude::*;
475/// # use async_coap::write_options;
476/// # use async_coap::{InboundContext, Error, message::MessageWrite};
477/// # use std::ops::Bound;
478/// # pub struct WriteOptionsExample<IC>(PhantomData<IC>);
479/// # impl<IC: InboundContext> SendDesc<IC, ()> for WriteOptionsExample<IC> {
480/// #
481/// fn write_options(
482///     &self,
483///     msg: &mut dyn OptionInsert,
484///     socket_addr: &IC::SocketAddr,
485///     start: Bound<OptionNumber>,
486///     end: Bound<OptionNumber>,
487/// ) -> Result<(), Error> {
488///     write_options!((msg, socket_addr, start, end) {
489///         // Note that the options **MUST** be listed **in numerical order**,
490///         // otherwise the behavior will be undefined!
491///         URI_HOST => Some("example.com").into_iter(),
492///         URI_PORT => Some(1234).into_iter(),
493///         URI_PATH => vec!["a","b","c"].into_iter(),
494///     })
495/// }
496/// #
497/// #    fn write_payload(&self,msg: &mut dyn MessageWrite, socket_addr: &IC::SocketAddr) -> Result<(), Error> {
498/// #        Ok(())
499/// #    }
500/// #    fn handler(&mut self,context: Result<&IC, Error>) -> Result<ResponseStatus<()>, Error> {
501/// #        context.map(|_| ResponseStatus::Done(()))
502/// #    }
503/// # }
504/// ```
505#[macro_export]
506macro_rules! write_options {
507    (($msg:expr, $socket_addr:expr, $start:expr, $end:expr, $inner:expr) { $($key:expr => $viter:expr),* }) => {{
508        let mut start = $start;
509        let end = $end;
510        let inner = &$inner;
511        let msg = $msg;
512        let socket_addr = $socket_addr;
513        #[allow(unused)]
514        use $crate::option::*;
515        #[allow(unused)]
516        use std::iter::once;
517
518        $( write_options!(_internal $key, $viter, start, end, msg, socket_addr, inner); )*
519
520        inner.write_options(msg, socket_addr, start, end)
521    }};
522
523    (($msg:expr, $socket_addr:expr, $start:expr, $end:expr) { $($key:expr => $viter:expr),* }) => {{
524        let mut start = $start;
525        let end = $end;
526        let msg = $msg;
527        let _socket_addr = $socket_addr;
528        #[allow(unused)]
529        use $crate::option::*;
530        #[allow(unused)]
531        use std::iter::once;
532
533        $( write_options!(_internal $key, $viter, start, end, msg, socket_addr); )*
534
535        let _ = start;
536
537        Ok(())
538    }};
539
540    (($msg:ident, $socket_addr:ident, $start:ident, $end:ident, $inner:expr) { $($key:expr => $viter:expr),* ,}) => {
541        write_options!(($msg,$socket_addr,$start,$end,$inner){$($key=>$viter),*})
542    };
543
544    (($msg:ident, $socket_addr:ident, $start:ident, $end:ident) { $($key:expr => $viter:expr),* ,}) => {
545        write_options!(($msg,$socket_addr,$start,$end){$($key=>$viter),*})
546    };
547
548    ( _internal $key:expr, $viter:expr, $start:ident, $end:ident, $msg:ident, $socket_addr:ident, $inner:expr) => {{
549        let key = $key;
550        let mut value_iter = $viter.into_iter().peekable();
551
552        if value_iter.peek().is_some()
553            && match $start {
554                Bound::Included(b) => b <= key.0,
555                Bound::Excluded(b) => b < key.0,
556                Bound::Unbounded => true,
557            }
558        {
559            if match $end {
560                Bound::Included(b) => key.0 <= b,
561                Bound::Excluded(b) => key.0 < b,
562                Bound::Unbounded => true,
563            } {
564                $inner.write_options($msg, $socket_addr, $start, Bound::Included(key.0))?;
565                for value in value_iter {
566                    $msg.insert_option(key, value)?;
567                }
568                $start = Bound::Excluded(key.0)
569            }
570        }
571    }};
572
573    ( _internal $key:expr, $viter:expr, $start:ident, $end:ident, $msg:ident, $socket_addr:ident) => {{
574        let key = $key;
575        let mut value_iter = $viter.into_iter().peekable();
576
577        if value_iter.peek().is_some()
578            && match $start {
579                Bound::Included(b) => b <= key.0,
580                Bound::Excluded(b) => b < key.0,
581                Bound::Unbounded => true,
582            }
583        {
584            if match $end {
585                Bound::Included(b) => key.0 <= b,
586                Bound::Excluded(b) => key.0 < b,
587                Bound::Unbounded => true,
588            } {
589                for value in value_iter {
590                    $msg.insert_option(key, value)?;
591                }
592                $start = Bound::Excluded(key.0)
593            }
594        }
595    }};
596}
597
598/// Helper macro that provides pass-thru implementations of the timing-related methods
599/// of a [`SendDesc`].
600///
601/// This macro takes a single argument: the name of the member variable to pass along
602/// the call to.
603#[doc(hidden)]
604#[macro_export]
605macro_rules! send_desc_passthru_timing {
606    ($inner:tt) => {
607        fn delay_to_retransmit(&self, retransmits_sent: u32) -> Option<::core::time::Duration> {
608            self.$inner.delay_to_retransmit(retransmits_sent)
609        }
610        fn delay_to_restart(&self) -> Option<::core::time::Duration> {
611            self.$inner.delay_to_restart()
612        }
613        fn max_rtt(&self) -> ::core::time::Duration {
614            self.$inner.max_rtt()
615        }
616        fn transmit_wait_duration(&self) -> ::core::time::Duration {
617            self.$inner.transmit_wait_duration()
618        }
619    }
620}
621
622/// Helper macro that provides pass-thru implementation of [`SendDesc::write_options`].
623///
624/// This macro takes a single argument: the name of the member variable to pass along
625/// the call to.
626#[doc(hidden)]
627#[macro_export]
628macro_rules! send_desc_passthru_options {
629    ($inner:tt) => {
630        fn write_options(
631            &self,
632            msg: &mut dyn OptionInsert,
633            socket_addr: &IC::SocketAddr,
634            start: Bound<OptionNumber>,
635            end: Bound<OptionNumber>,
636        ) -> Result<(), Error> {
637            self.$inner.write_options(msg, socket_addr, start, end)
638        }
639    }
640}
641
642/// Helper macro that provides pass-thru implementations of [`SendDesc::handler`] and
643/// [`SendDesc::supports_option`].
644///
645/// This macro takes a single argument: the name of the member variable to pass along
646/// the call to.
647#[doc(hidden)]
648#[macro_export]
649macro_rules! send_desc_passthru_handler {
650    ($inner:tt, $rt:ty) => {
651        fn supports_option(&self, option: OptionNumber) -> bool {
652            self.$inner.supports_option(option)
653        }
654        fn handler(&mut self, context: Result<&IC, Error>) -> Result<ResponseStatus<$rt>, Error> {
655            self.$inner.handler(context)
656        }
657    };
658
659    ($inner:tt) => {
660        send_desc_passthru_handler!($inner, ());
661    }
662}
663
664/// Helper macro that provides pass-thru implementation of [`SendDesc::supports_option`].
665///
666/// This macro takes a single argument: the name of the member variable to pass along
667/// the call to.
668#[doc(hidden)]
669#[macro_export]
670macro_rules! send_desc_passthru_supports_option {
671    ($inner:tt) => {
672        fn supports_option(&self, option: OptionNumber) -> bool {
673            self.$inner.supports_option(option)
674        }
675    }
676}
677
678/// Helper macro that provides pass-thru implementation of [`SendDesc::write_payload`].
679///
680/// This macro takes a single argument: the name of the member variable to pass along
681/// the call to.
682#[doc(hidden)]
683#[macro_export]
684macro_rules! send_desc_passthru_payload {
685    ($inner:tt) => {
686        fn write_payload(
687            &self,
688            msg: &mut dyn MessageWrite,
689            socket_addr: &IC::SocketAddr,
690        ) -> Result<(), Error> {
691            self.$inner.write_payload(msg, socket_addr)
692        }
693    }
694}