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}