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}