Skip to main content

iri_string/types/generic/
query.rs

1//! Query string.
2
3use crate::spec::Spec;
4use crate::validate::{query, Error, ErrorKind};
5
6define_custom_string_slice! {
7    /// A borrowed slice of an IRI query (i.e. after the first `?` and before the first `#`).
8    ///
9    /// This corresponds to [`iquery` rule] in [RFC 3987] (and [`query` rule] in [RFC 3986]).
10    /// The rule for `iquery` is `*( ipchar / iprivate / "/" / "?" )`.
11    ///
12    /// # Valid values
13    ///
14    /// This type can have an IRI query string.
15    /// Note that the IRI `foo://bar/baz?qux` has the query `qux`, **not** `?qux`.
16    ///
17    /// ```
18    /// use iri_string::types::IriQueryStr;
19    /// assert!(IriQueryStr::new("").is_ok());
20    /// assert!(IriQueryStr::new("foo").is_ok());
21    /// assert!(IriQueryStr::new("foo/bar").is_ok());
22    /// assert!(IriQueryStr::new("/foo/bar").is_ok());
23    /// assert!(IriQueryStr::new("//foo/bar").is_ok());
24    /// assert!(IriQueryStr::new("https://user:pass@example.com:8080").is_ok());
25    /// assert!(IriQueryStr::new("https://example.com/").is_ok());
26    /// // Question sign `?` can appear in an IRI query.
27    /// assert!(IriQueryStr::new("query?again").is_ok());
28    /// ```
29    ///
30    /// Some characters and sequences cannot used in a query.
31    ///
32    /// ```
33    /// use iri_string::types::IriQueryStr;
34    /// // `<` and `>` cannot directly appear in an IRI reference.
35    /// assert!(IriQueryStr::new("<not allowed>").is_err());
36    /// // Broken percent encoding cannot appear in an IRI reference.
37    /// assert!(IriQueryStr::new("%").is_err());
38    /// assert!(IriQueryStr::new("%GG").is_err());
39    /// // Hash sign `#` cannot appear in an IRI query.
40    /// assert!(IriQueryStr::new("#hash").is_err());
41    /// ```
42    ///
43    /// [RFC 3986]: https://www.rfc-editor.org/rfc/rfc3986.html
44    /// [RFC 3987]: https://www.rfc-editor.org/rfc/rfc3987.html
45    /// [`query` rule]: https://www.rfc-editor.org/rfc/rfc3986.html#section-3.4
46    /// [`iquery` rule]: https://www.rfc-editor.org/rfc/rfc3987.html#section-2.2
47    struct RiQueryStr {
48        validator = query,
49        expecting_msg = "IRI query string",
50    }
51}
52
53#[cfg(feature = "alloc")]
54define_custom_string_owned! {
55    /// A owned slice of an IRI query (i.e. after the first `?` and before the first `#`).
56    ///
57    /// This corresponds to [`iquery` rule] in [RFC 3987] (and [`query` rule] in [RFC 3986]).
58    /// The rule for `iquery` is `*( ipchar / iprivate / "/" / "?" )`.
59    ///
60    /// For details, see the documentation for [`RiQueryStr`].
61    ///
62    /// Enabled by `alloc` or `std` feature.
63    ///
64    /// [RFC 3986]: https://www.rfc-editor.org/rfc/rfc3986.html
65    /// [RFC 3987]: https://www.rfc-editor.org/rfc/rfc3987.html
66    /// [`query` rule]: https://www.rfc-editor.org/rfc/rfc3986.html#section-3.4
67    /// [`iquery` rule]: https://www.rfc-editor.org/rfc/rfc3987.html#section-2.2
68    /// [`RiQueryStr`]: struct.RiQueryStr.html
69    struct RiQueryString {
70        validator = query,
71        slice = RiQueryStr,
72        expecting_msg = "IRI query string",
73    }
74}
75
76impl<S: Spec> RiQueryStr<S> {
77    /// Creates a new `&RiQueryStr` from the query part prefixed by `?`.
78    ///
79    /// # Examples
80    ///
81    /// ```
82    /// # use iri_string::types::IriQueryStr;
83    /// assert!(IriQueryStr::from_prefixed("?").is_ok());
84    /// assert!(IriQueryStr::from_prefixed("?foo").is_ok());
85    /// assert!(IriQueryStr::from_prefixed("?foo/bar").is_ok());
86    /// assert!(IriQueryStr::from_prefixed("?/foo/bar").is_ok());
87    /// assert!(IriQueryStr::from_prefixed("?//foo/bar").is_ok());
88    /// assert!(IriQueryStr::from_prefixed("?https://user:pass@example.com:8080").is_ok());
89    /// assert!(IriQueryStr::from_prefixed("?https://example.com/").is_ok());
90    /// // Question sign `?` can appear in an IRI query.
91    /// assert!(IriQueryStr::from_prefixed("?query?again").is_ok());
92    ///
93    /// // `<` and `>` cannot directly appear in an IRI.
94    /// assert!(IriQueryStr::from_prefixed("?<not allowed>").is_err());
95    /// // Broken percent encoding cannot appear in an IRI.
96    /// assert!(IriQueryStr::new("?%").is_err());
97    /// assert!(IriQueryStr::new("?%GG").is_err());
98    /// // `?` prefix is expected.
99    /// assert!(IriQueryStr::from_prefixed("").is_err());
100    /// assert!(IriQueryStr::from_prefixed("foo").is_err());
101    /// // Hash sign `#` cannot appear in an IRI query.
102    /// assert!(IriQueryStr::from_prefixed("?#hash").is_err());
103    /// ```
104    pub fn from_prefixed(s: &str) -> Result<&Self, Error> {
105        if !s.starts_with('?') {
106            return Err(Error::with_kind(ErrorKind::InvalidQuery));
107        }
108        TryFrom::try_from(&s[1..])
109    }
110}