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}