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