async_coap/send_desc/
request.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
16use super::*;
17
18/// Seed combinator used for creating send descriptors for CoAP requests.
19#[derive(Debug)]
20pub enum CoapRequest {}
21
22impl CoapRequest {
23    /// Constructs a simple GET send descriptor.
24    ///
25    /// The generic parameter `IC` can (for the most part) be ignored: the type will be
26    /// inferred when the send descriptor is passed to [`LocalEndpoint::send`] (or one of its
27    /// [many][RemoteEndpoint::send_to] [variants][RemoteEndpoint::send]).
28    #[inline(always)]
29    pub fn get<IC>() -> SendGet<IC> {
30        Default::default()
31    }
32
33    /// Constructs a simple GET send descriptor configured for observing.
34    ///
35    /// The generic parameter `IC` can (for the most part) be ignored: the type will be
36    /// inferred when the send descriptor is passed to [`LocalEndpointExt::send_as_stream`] (or
37    /// one of its [many][RemoteEndpointExt::send_to_as_stream]
38    /// [variants][RemoteEndpointExt::send_as_stream]).
39    #[inline(always)]
40    pub fn observe<IC>() -> SendObserve<IC> {
41        Default::default()
42    }
43
44    /// Constructs a simple POST send descriptor.
45    ///
46    /// The generic parameter `IC` can (for the most part) be ignored: the type will be
47    /// inferred when the send descriptor is passed to [`LocalEndpoint::send`] (or one of its
48    /// [many][RemoteEndpoint::send_to] [variants][RemoteEndpoint::send]).
49    #[inline(always)]
50    pub fn post<IC>() -> SendPost<IC> {
51        Default::default()
52    }
53
54    /// Constructs a simple PUT send descriptor.
55    ///
56    /// The generic parameter `IC` can (for the most part) be ignored: the type will be
57    /// inferred when the send descriptor is passed to [`LocalEndpoint::send`] (or one of its
58    /// [many][RemoteEndpoint::send_to] [variants][RemoteEndpoint::send]).
59    #[inline(always)]
60    pub fn put<IC>() -> SendPut<IC> {
61        Default::default()
62    }
63
64    /// Constructs a simple DELETE send descriptor.
65    ///
66    /// The generic parameter `IC` can (for the most part) be ignored: the type will be
67    /// inferred when the send descriptor is passed to [`LocalEndpoint::send`] (or one of its
68    /// [many][RemoteEndpoint::send_to] [variants][RemoteEndpoint::send]).
69    #[inline(always)]
70    pub fn delete<IC>() -> SendDelete<IC> {
71        Default::default()
72    }
73
74    /// Constructs a simple send descriptor with an arbitrary CoAP method code.
75    ///
76    /// The value of `msg_code` is checked in debug mode to ensure it is a CoAP method.
77    /// The value is not checked in release mode.
78    ///
79    /// The generic parameter `IC` can (for the most part) be ignored: the type will be
80    /// inferred when the send descriptor is passed to [`LocalEndpoint::send`] (or one of its
81    /// [many][RemoteEndpoint::send_to] [variants][RemoteEndpoint::send]).
82    #[inline(always)]
83    pub fn method<IC>(msg_code: MsgCode) -> CoapRequestMethod<IC> {
84        debug_assert!(msg_code.is_method(), "{:?} is not a method", msg_code);
85        CoapRequestMethod {
86            msg_code,
87            phantom: PhantomData,
88        }
89    }
90}
91
92macro_rules! send_desc_def_method {
93    ($(#[$tags:meta])* $name:ident, $code:expr, $handler:expr) => {
94        $(#[$tags])*
95        #[derive(Debug)]
96        pub struct $ name < IC > (PhantomData < IC > );
97        send_desc_def_method!(@rest ($name,$code,$handler));
98    };
99    ($name:ident, $code:expr, $handler:expr) => {
100        pub struct $ name < IC > (PhantomData < IC > );
101        send_desc_def_method!(@rest ($name,$code,$handler));
102    };
103    (@rest ($name:ident, $code:expr, $handler:expr)) => {
104        impl<IC> SendDescUnicast for $name<IC> {}
105
106        impl<IC> Default for $name<IC> {
107            #[inline(always)]
108            fn default() -> Self {
109                Self(PhantomData)
110            }
111        }
112
113        impl<IC> $name<IC> {
114            /// Returns a nonconfirmable version of this send descriptor.
115            #[inline(always)]
116            pub fn nonconfirmable(self) -> Nonconfirmable<$name<IC>> {
117                Nonconfirmable(self)
118            }
119
120            /// Returns a multicast version of this send descriptor.
121            #[inline(always)]
122            pub fn multicast(self) -> Multicast<$name<IC>> {
123                Multicast(self)
124            }
125        }
126
127        impl<IC: InboundContext> SendDesc<IC, ()> for $name<IC> {
128            fn write_options(
129                &self,
130                _msg: &mut dyn OptionInsert,
131                _socket_addr: &IC::SocketAddr,
132                _start: Bound<OptionNumber>,
133                _end: Bound<OptionNumber>,
134            ) -> Result<(), Error> {
135                Ok(())
136            }
137
138            fn write_payload(
139                &self,
140                msg: &mut dyn MessageWrite,
141                _socket_addr: &IC::SocketAddr,
142            ) -> Result<(), Error> {
143                msg.set_msg_code($code);
144                Ok(())
145            }
146
147            fn handler(
148                &mut self,
149                context: Result<&IC, Error>,
150            ) -> Result<ResponseStatus<()>, Error> {
151                let context = context?;
152
153                if context.is_dupe() {
154                    // Ignore dupes.
155                    return Ok(ResponseStatus::Continue);
156                }
157
158                let code = context.message().msg_code();
159                ($handler)(code)
160            }
161        }
162    };
163}
164
165send_desc_def_method!(
166    /// Send descriptor created by [`CoapRequest::get`] used for sending CoAP GET requests.
167    SendGet,
168    MsgCode::MethodGet,
169    |code| {
170        match code {
171            MsgCode::SuccessContent | MsgCode::SuccessValid => Ok(ResponseStatus::Done(())),
172            MsgCode::ClientErrorNotFound => Err(Error::ResourceNotFound),
173            MsgCode::ClientErrorForbidden => Err(Error::Forbidden),
174            MsgCode::ClientErrorUnauthorized => Err(Error::Unauthorized),
175            code if code.is_client_error() => Err(Error::ClientRequestError),
176            _ => Err(Error::ServerError),
177        }
178    }
179);
180
181send_desc_def_method!(
182    /// Send descriptor created by [`CoapRequest::put`] used for sending CoAP PUT requests.
183    SendPut,
184    MsgCode::MethodPut,
185    |code| {
186        match code {
187            MsgCode::SuccessCreated | MsgCode::SuccessChanged | MsgCode::SuccessValid => {
188                Ok(ResponseStatus::Done(()))
189            }
190            MsgCode::ClientErrorNotFound => Err(Error::ResourceNotFound),
191            MsgCode::ClientErrorForbidden => Err(Error::Forbidden),
192            MsgCode::ClientErrorUnauthorized => Err(Error::Unauthorized),
193            code if code.is_client_error() => Err(Error::ClientRequestError),
194            _ => Err(Error::ServerError),
195        }
196    }
197);
198
199send_desc_def_method!(
200    /// Send descriptor created by [`CoapRequest::post`] used for sending CoAP POST requests.
201    SendPost,
202    MsgCode::MethodPost,
203    |code| {
204        match code {
205            code if code.is_success() => Ok(ResponseStatus::Done(())),
206            MsgCode::ClientErrorNotFound => Err(Error::ResourceNotFound),
207            MsgCode::ClientErrorForbidden => Err(Error::Forbidden),
208            MsgCode::ClientErrorUnauthorized => Err(Error::Unauthorized),
209            code if code.is_client_error() => Err(Error::ClientRequestError),
210            _ => Err(Error::ServerError),
211        }
212    }
213);
214
215send_desc_def_method!(
216    /// Send descriptor created by [`CoapRequest::delete`] used for sending CoAP DELETE requests.
217    SendDelete,
218    MsgCode::MethodDelete,
219    |code| {
220        match code {
221            MsgCode::SuccessDeleted => Ok(ResponseStatus::Done(())),
222            MsgCode::ClientErrorNotFound => Err(Error::ResourceNotFound),
223            MsgCode::ClientErrorForbidden => Err(Error::Forbidden),
224            MsgCode::ClientErrorUnauthorized => Err(Error::Unauthorized),
225            code if code.is_client_error() => Err(Error::ClientRequestError),
226            _ => Err(Error::ServerError),
227        }
228    }
229);
230
231/// Send descriptor created by [`CoapRequest::method`] used for sending CoAP requests with a
232/// programmatically defined method.
233#[derive(Debug)]
234pub struct CoapRequestMethod<IC> {
235    msg_code: MsgCode,
236    phantom: PhantomData<IC>,
237}
238
239impl<IC> SendDescUnicast for CoapRequestMethod<IC> {}
240
241impl<IC> CoapRequestMethod<IC> {
242    /// Returns a nonconfirmable version of this send descriptor.
243    #[inline(always)]
244    pub fn nonconfirmable(self) -> Nonconfirmable<CoapRequestMethod<IC>> {
245        Nonconfirmable(self)
246    }
247
248    /// Returns a multicast version of this send descriptor.
249    #[inline(always)]
250    pub fn multicast(self) -> Multicast<CoapRequestMethod<IC>> {
251        Multicast(self)
252    }
253}
254
255impl<IC> SendDesc<IC, ()> for CoapRequestMethod<IC>
256where
257    IC: InboundContext,
258{
259    fn write_options(
260        &self,
261        _msg: &mut dyn OptionInsert,
262        _socket_addr: &IC::SocketAddr,
263        _start: Bound<OptionNumber>,
264        _end: Bound<OptionNumber>,
265    ) -> Result<(), Error> {
266        Ok(())
267    }
268
269    fn write_payload(
270        &self,
271        msg: &mut dyn MessageWrite,
272        _socket_addr: &IC::SocketAddr,
273    ) -> Result<(), Error> {
274        msg.set_msg_code(self.msg_code);
275        Ok(())
276    }
277
278    fn handler(&mut self, context: Result<&IC, Error>) -> Result<ResponseStatus<()>, Error> {
279        let context = context?;
280
281        if context.is_dupe() {
282            // Ignore dupes.
283            return Ok(ResponseStatus::Continue);
284        }
285
286        let code = context.message().msg_code();
287
288        match code {
289            code if code.is_success() => Ok(ResponseStatus::Done(())),
290            MsgCode::ClientErrorNotFound => Err(Error::ResourceNotFound),
291            MsgCode::ClientErrorForbidden => Err(Error::Forbidden),
292            MsgCode::ClientErrorUnauthorized => Err(Error::Unauthorized),
293            code if code.is_client_error() => Err(Error::ClientRequestError),
294            _ => Err(Error::ServerError),
295        }
296    }
297}