iri_string/types/generic/
query.rs

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