async_coap_uri/macros.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//! Module containing all of macro definitions for `async-coap-uri`.
17
18pub use super::{impl_uri_buf_traits, impl_uri_traits};
19pub use super::{rel_ref, uri, uri_ref};
20pub use super::{rel_ref_format, uri_format, uri_ref_format};
21
22// Internal macros.
23#[doc(hidden)]
24pub use super::{_impl_uri_buf_traits_base, _impl_uri_traits, _impl_uri_traits_base};
25
26#[doc(hidden)]
27#[macro_export]
28macro_rules! _uri_const {
29 ( $S:expr, $C:ty ) => {{
30 const __CONST_S: &'static str = $S;
31 // We do this weird casting thing here to make sure that we
32 // don't end up using unstable features, while still allowing
33 // these macros to be used to assign constants.
34 unsafe {
35 union Slices<'a> {
36 str: &'a str,
37 uri: &'a $C,
38 }
39 Slices { str: __CONST_S }.uri
40 }
41 }};
42}
43
44/// Creates a `&'static UriRef` from a string literal.
45///
46/// Accepts only string constants and literals. The given string *MUST* be well-formed.
47///
48/// Examples:
49///
50/// ```
51/// # use async_coap_uri::prelude::*;
52/// let x = uri_ref!("a/b/c?q=foobar#frag");
53/// assert_eq!(x.scheme(),None);
54/// assert_eq!(x.raw_authority(),None);
55/// assert_eq!(x.raw_path(),"a/b/c");
56/// assert_eq!(x.raw_query(),Some("q=foobar"));
57/// assert_eq!(x.raw_fragment(),Some("frag"));
58/// ```
59///
60/// ```
61/// # use async_coap_uri::prelude::*;
62/// let x = uri_ref!("http://example.com");
63/// assert_eq!(x.scheme(),Some("http"));
64/// assert_eq!(x.raw_authority(),Some("example.com"));
65/// assert_eq!(x.raw_path(),"");
66/// assert_eq!(x.raw_query(),None);
67/// assert_eq!(x.raw_fragment(),None);
68/// ```
69///
70/// Checks for correctness are performed at compile time:
71///
72/// ```compile_fail
73/// # use async_coap_uri::prelude::*;
74/// // This will not compile.
75/// let x = uri_ref!("%00 invalid %ff");
76/// ```
77///
78#[macro_export]
79macro_rules! uri_ref {
80 ( unsafe $S:expr ) => {{
81 // We don't do any correctness checks when $S is preceded by `unsafe`.
82 $crate::_uri_const!($S, $crate::UriRef)
83 }};
84 ( $S:expr ) => {{
85 assert_uri_ref_literal!($S);
86 $crate::_uri_const!($S, $crate::UriRef)
87 }};
88 ( ) => {
89 $crate::uri_ref!("")
90 };
91}
92
93/// Creates a `&'static RelRef` from a string literal.
94///
95/// Accepts only string constants and literals. The given string *MUST* be well-formed.
96///
97/// Example:
98///
99/// ```
100/// # use async_coap_uri::prelude::*;
101/// let x = rel_ref!("a/b/c?q=foobar#frag");
102/// assert_eq!(x.raw_path(),"a/b/c");
103/// assert_eq!(x.raw_query(),Some("q=foobar"));
104/// assert_eq!(x.raw_fragment(),Some("frag"));
105/// ```
106///
107/// Checks for correctness are performed at compile time:
108///
109/// ```compile_fail
110/// # use async_coap_uri::prelude::*;
111/// // This will not compile.
112/// let x = rel_ref!("%00 invalid %ff");
113/// ```
114///
115/// Degenerate cases (strings that could be confused with URIs if parsed as URI-Refs)
116/// will also not compile:
117///
118/// ```compile_fail
119/// # use async_coap_uri::prelude::*;
120/// // This will not compile because `//a/b/c` is
121/// // a degenerate relative reference.
122/// let x = rel_ref!("//a/b/c");
123/// ```
124///
125/// ```compile_fail
126/// # use async_coap_uri::prelude::*;
127/// // This will not compile because `g:a:b:c` is
128/// // a degenerate relative reference.
129/// let x = rel_ref!("g:a:b:c");
130/// ```
131///
132/// Both of those cases can be made to compile by adjusting them to no longer be degenerate:
133///
134/// ```
135/// # use async_coap_uri::prelude::*;
136/// let b = rel_ref!("/.//a/b/c"); // Prepending "/."
137/// let a = rel_ref!("./g:a:b:c"); // Prepending "./"
138/// let a = rel_ref!("g%3Aa:b:c"); // Convert first colon to "%3A"
139/// ```
140///
141/// At runtime, `UriRef::from_str("g:a:b:c")` is allowed since in some circumstances it cannot
142/// be avoided, but there is usually no good reason to have a degenerate `RelRef` literal.
143/// In the rare case where such a thing is warranted (unit tests, for example), you can disable
144/// compile-time verification by prepending the keyword `unsafe` to the string:
145///
146/// ```
147/// # use async_coap_uri::prelude::*;
148/// // Both of these will compile because the `unsafe` keyword
149/// // disables the compile-time validity checks:
150/// assert!(rel_ref!(unsafe "//a/b/c").is_degenerate());
151/// assert!(rel_ref!(unsafe "g:a:b:c").is_degenerate());
152/// ```
153#[macro_export]
154macro_rules! rel_ref {
155 ( unsafe $S:expr ) => {{
156 // We don't do any correctness checks when $S is preceded by `unsafe`.
157 $crate::_uri_const!($S, $crate::RelRef)
158 }};
159 ( $S:expr ) => {{
160 assert_rel_ref_literal!($S);
161 $crate::_uri_const!($S, $crate::RelRef)
162 }};
163 ( ) => {
164 $crate::rel_ref!("")
165 };
166}
167
168/// Creates a `&'static Uri` from a string literal.
169///
170/// Accepts only string constants and literals. The given string *MUST* be well-formed.
171///
172/// Example:
173///
174/// ```
175/// # use async_coap_uri::prelude::*;
176/// let x = uri!("http://example.com");
177/// assert_eq!(x.scheme(),Some("http"));
178/// assert_eq!(x.raw_authority(),Some("example.com"));
179/// ```
180///
181/// Checks for correctness are performed at compile time:
182///
183/// ```compile_fail
184/// # use async_coap_uri::prelude::*;
185/// // This will not compile.
186/// let x = uri!("%00 invalid %ff");
187/// ```
188///
189/// Passing something that is a valid URI-Reference but not a valid URI (i.e.: Missing scheme)
190/// will also not compile:
191///
192/// ```compile_fail
193/// # use async_coap_uri::prelude::*;
194/// // This will not compile because "a/b/c" isn't a valid URI.
195/// let x = uri!("a/b/c");
196/// ```
197///
198#[macro_export]
199macro_rules! uri {
200 ( unsafe $S:expr ) => {{
201 // We don't do any correctness checks when $S is preceded by `unsafe`.
202 $crate::_uri_const!($S, $crate::Uri)
203 }};
204 ( $S:expr ) => {{
205 assert_uri_literal!($S);
206 $crate::_uri_const!($S, $crate::Uri)
207 }};
208 ( ) => {
209 $crate::uri!("")
210 };
211}
212
213/// Creates a `Option<UriRefBuf>` from the given string format and arguments.
214///
215/// The resulting string is checked at runtime to ensure it is well-formed.
216#[cfg(feature = "std")]
217#[macro_export]
218macro_rules! uri_ref_format {
219 ($($arg:tt)*) => ($crate::UriRefBuf::from_string(format!($($arg)*)))
220}
221
222/// Creates a `Option<UriBuf>` from the given string format and arguments.
223///
224/// The resulting string is checked at runtime to ensure it is well-formed.
225#[cfg(feature = "std")]
226#[macro_export]
227macro_rules! uri_format {
228 ($($arg:tt)*) => ($crate::UriBuf::from_string(format!($($arg)*)))
229}
230
231/// Creates a `Option<RelRefBuf>` from the given string format and arguments.
232///
233/// The resulting string is checked at runtime to ensure it is well-formed.
234#[cfg(feature = "std")]
235#[macro_export]
236macro_rules! rel_ref_format {
237 ($($arg:tt)*) => ($crate::RelRefBuf::from_string(format!($($arg)*)))
238}
239
240#[doc(hidden)]
241#[macro_export]
242macro_rules! _impl_uri_traits {
243 ( $C:ty ) => {
244 impl<T: AsRef<str> + ?Sized> core::cmp::PartialEq<T> for $C {
245 fn eq(&self, other: &T) -> bool {
246 core::cmp::PartialEq::eq(self.as_str(), other.as_ref())
247 }
248 }
249
250 impl<T: AsRef<str> + ?Sized> core::cmp::PartialOrd<T> for $C {
251 fn partial_cmp(&self, other: &T) -> Option<::std::cmp::Ordering> {
252 core::cmp::PartialOrd::partial_cmp(self.as_str(), other.as_ref())
253 }
254 }
255
256 impl core::cmp::Ord for $C {
257 fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
258 core::cmp::Ord::cmp(self.as_str(), other.as_str())
259 }
260 }
261
262 impl std::fmt::Debug for $C {
263 fn fmt(
264 &self,
265 f: &mut std::fmt::Formatter<'_>,
266 ) -> std::result::Result<(), std::fmt::Error> {
267 f.write_str(concat!(stringify!($C), "<"))?;
268 std::fmt::Display::fmt(self.as_str(), f)?;
269 f.write_str(">")
270 }
271 }
272 impl AsRef<str> for $C {
273 fn as_ref(&self) -> &str {
274 self.as_str()
275 }
276 }
277 impl AsRef<$C> for $C {
278 fn as_ref(&self) -> &$C {
279 &self
280 }
281 }
282 };
283}
284
285#[doc(hidden)]
286#[macro_export]
287macro_rules! _impl_uri_traits_base {
288 ( $C:ty ) => {
289 _impl_uri_traits!($C);
290
291 impl core::convert::From<&$C> for std::string::String {
292 fn from(x: &$C) -> Self {
293 String::from(&x.0)
294 }
295 }
296
297 impl core::convert::From<&$C> for $crate::UriRefBuf {
298 fn from(x: &$C) -> Self {
299 unsafe { $crate::UriRefBuf::from_string_unchecked(String::from(&x.0)) }
300 }
301 }
302 };
303}
304
305#[doc(hidden)]
306#[macro_export]
307macro_rules! impl_uri_traits {
308 ( $C:ty ) => {
309 _impl_uri_traits_base!($C);
310
311 impl $crate::AnyUriRef for $C {
312 fn components(&self) -> UriRawComponents<'_> {
313 self.0.components()
314 }
315
316 fn write_to<W: core::fmt::Write + ?Sized>(
317 &self,
318 write: &mut W,
319 ) -> Result<(), core::fmt::Error> {
320 self.0.write_to(write)
321 }
322
323 fn is_empty(&self) -> bool {
324 self.0.is_empty()
325 }
326
327 fn uri_type(&self) -> $crate::UriType {
328 self.0.uri_type()
329 }
330
331 fn to_uri_ref_buf(&self) -> $crate::UriRefBuf {
332 self.0.to_uri_ref_buf()
333 }
334
335 fn write_resolved<W: core::fmt::Write + ?Sized, D: $crate::AnyUriRef + ?Sized>(
336 &self,
337 dest: &D,
338 output: &mut W,
339 ) -> Result<(), $crate::ResolveError> {
340 self.0.write_resolved(dest, output)
341 }
342
343 fn resolved<W: $crate::AnyUriRef + ?Sized>(
344 &self,
345 dest: &W,
346 ) -> Result<$crate::UriRefBuf, $crate::ResolveError> {
347 self.0.resolved(dest)
348 }
349 }
350 };
351}
352
353#[doc(hidden)]
354#[macro_export]
355macro_rules! _impl_uri_buf_traits_base {
356 ( $C:ty , $B:ty ) => {
357 _impl_uri_traits!($C);
358
359 impl core::convert::From<$C> for std::string::String {
360 fn from(x: $C) -> Self {
361 String::from(x.0)
362 }
363 }
364
365 impl core::convert::From<&$C> for $C {
366 fn from(x: &$C) -> Self {
367 x.clone()
368 }
369 }
370
371 impl std::borrow::ToOwned for $B {
372 type Owned = $C;
373
374 fn to_owned(&self) -> Self::Owned {
375 unsafe { <$C>::from_string_unchecked(self.to_string()) }
376 }
377 }
378
379 impl core::borrow::Borrow<$B> for $C {
380 fn borrow(&self) -> &$B {
381 unsafe { <$B>::from_str_unchecked(self.as_str()) }
382 }
383 }
384
385 impl $crate::AnyUriRef for $C {
386 fn components(&self) -> UriRawComponents<'_> {
387 use core::borrow::Borrow;
388 let b: &$B = self.borrow();
389 b.components()
390 }
391
392 fn write_to<W: core::fmt::Write + ?Sized>(
393 &self,
394 write: &mut W,
395 ) -> Result<(), core::fmt::Error> {
396 use core::borrow::Borrow;
397 let b: &$B = self.borrow();
398 b.write_to(write)
399 }
400
401 fn is_empty(&self) -> bool {
402 use core::borrow::Borrow;
403 let b: &$B = self.borrow();
404 b.is_empty()
405 }
406
407 fn uri_type(&self) -> $crate::UriType {
408 use core::borrow::Borrow;
409 let b: &$B = self.borrow();
410 b.uri_type()
411 }
412
413 fn to_uri_ref_buf(&self) -> $crate::UriRefBuf {
414 use core::borrow::Borrow;
415 let b: &$B = self.borrow();
416 b.to_uri_ref_buf()
417 }
418
419 fn write_resolved<W: core::fmt::Write + ?Sized, D: $crate::AnyUriRef + ?Sized>(
420 &self,
421 dest: &D,
422 output: &mut W,
423 ) -> Result<(), $crate::ResolveError> {
424 use core::borrow::Borrow;
425 let b: &$B = self.borrow();
426 b.write_resolved(dest, output)
427 }
428
429 fn resolved<W: $crate::AnyUriRef + ?Sized>(
430 &self,
431 dest: &W,
432 ) -> Result<$crate::UriRefBuf, $crate::ResolveError> {
433 use core::borrow::Borrow;
434 let b: &$B = self.borrow();
435 b.resolved(dest)
436 }
437 }
438 };
439}
440
441#[doc(hidden)]
442#[macro_export]
443macro_rules! impl_uri_buf_traits {
444 ( $C:ty , $B:ty) => {
445 _impl_uri_buf_traits_base!($C, $B);
446
447 impl AsRef<std::string::String> for $C {
448 fn as_ref(&self) -> &std::string::String {
449 AsRef::<std::string::String>::as_ref(&self.0)
450 }
451 }
452
453 impl AsRef<$crate::UriRefBuf> for $C {
454 fn as_ref(&self) -> &$crate::UriRefBuf {
455 AsRef::<$crate::UriRefBuf>::as_ref(&self.0)
456 }
457 }
458
459 impl core::convert::From<$C> for $crate::UriRefBuf {
460 fn from(x: $C) -> Self {
461 x.0.into()
462 }
463 }
464 };
465}