iri_string/validate.rs
1//! Validators.
2
3use core::fmt;
4
5#[cfg(feature = "std")]
6use std::error;
7
8use crate::parser::validate as parser;
9use crate::spec::Spec;
10
11/// Resource identifier validation error.
12// Note that this type should implement `Copy` trait.
13// To return additional non-`Copy` data as an error, use wrapper type
14// (as `std::string::FromUtf8Error` contains `std::str::Utf8Error`).
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub struct Error(());
17
18impl Error {
19 /// Creates a new `Error`.
20 ///
21 /// For internal use.
22 #[inline]
23 #[must_use]
24 pub(crate) fn new() -> Self {
25 Error(())
26 }
27}
28
29impl fmt::Display for Error {
30 #[inline]
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 f.write_str("Invalid IRI")
33 }
34}
35
36#[cfg(feature = "std")]
37impl error::Error for Error {}
38
39/// Validates [IRI][uri].
40///
41/// This validator corresponds to [`RiStr`] and [`RiString`] types.
42///
43/// # Examples
44///
45/// This type can have an IRI (which is absolute, and may have fragment part).
46///
47/// ```
48/// use iri_string::{spec::UriSpec, validate::iri};
49/// assert!(iri::<UriSpec>("https://user:pass@example.com:8080").is_ok());
50/// assert!(iri::<UriSpec>("https://example.com/").is_ok());
51/// assert!(iri::<UriSpec>("https://example.com/foo?bar=baz").is_ok());
52/// assert!(iri::<UriSpec>("https://example.com/foo?bar=baz#qux").is_ok());
53/// assert!(iri::<UriSpec>("foo:bar").is_ok());
54/// assert!(iri::<UriSpec>("foo:").is_ok());
55/// // `foo://.../` below are all allowed. See the crate documentation for detail.
56/// assert!(iri::<UriSpec>("foo:/").is_ok());
57/// assert!(iri::<UriSpec>("foo://").is_ok());
58/// assert!(iri::<UriSpec>("foo:///").is_ok());
59/// assert!(iri::<UriSpec>("foo:////").is_ok());
60/// assert!(iri::<UriSpec>("foo://///").is_ok());
61/// ```
62///
63/// Relative IRI reference is not allowed.
64///
65/// ```
66/// use iri_string::{spec::UriSpec, validate::iri};
67/// // This is relative path.
68/// assert!(iri::<UriSpec>("foo/bar").is_err());
69/// // `/foo/bar` is an absolute path, but it is authority-relative.
70/// assert!(iri::<UriSpec>("/foo/bar").is_err());
71/// // `//foo/bar` is termed "network-path reference",
72/// // or usually called "protocol-relative reference".
73/// assert!(iri::<UriSpec>("//foo/bar").is_err());
74/// // Same-document reference is relative.
75/// assert!(iri::<UriSpec>("#foo").is_err());
76/// // Empty string is not a valid absolute IRI.
77/// assert!(iri::<UriSpec>("").is_err());
78/// ```
79///
80/// Some characters and sequences cannot used in an IRI.
81///
82/// ```
83/// use iri_string::{spec::UriSpec, validate::iri};
84/// // `<` and `>` cannot directly appear in an IRI.
85/// assert!(iri::<UriSpec>("<not allowed>").is_err());
86/// // Broken percent encoding cannot appear in an IRI.
87/// assert!(iri::<UriSpec>("%").is_err());
88/// assert!(iri::<UriSpec>("%GG").is_err());
89/// ```
90///
91/// [uri]: https://tools.ietf.org/html/rfc3986#section-3
92/// [`RiStr`]: ../types/struct.RiStr.html
93/// [`RiString`]: ../types/struct.RiString.html
94pub fn iri<S: Spec>(s: &str) -> Result<(), Error> {
95 parser::validate_uri::<S>(s)
96}
97
98/// Validates [IRI reference][uri-reference].
99///
100/// This validator corresponds to [`RiReferenceStr`] and [`RiReferenceString`] types.
101///
102/// # Examples
103///
104/// This type can have an IRI reference (which can be absolute or relative).
105///
106/// ```
107/// use iri_string::{spec::UriSpec, validate::iri_reference};
108/// assert!(iri_reference::<UriSpec>("https://user:pass@example.com:8080").is_ok());
109/// assert!(iri_reference::<UriSpec>("https://example.com/").is_ok());
110/// assert!(iri_reference::<UriSpec>("https://example.com/foo?bar=baz").is_ok());
111/// assert!(iri_reference::<UriSpec>("https://example.com/foo?bar=baz#qux").is_ok());
112/// assert!(iri_reference::<UriSpec>("foo:bar").is_ok());
113/// assert!(iri_reference::<UriSpec>("foo:").is_ok());
114/// // `foo://.../` below are all allowed. See the crate documentation for detail.
115/// assert!(iri_reference::<UriSpec>("foo:/").is_ok());
116/// assert!(iri_reference::<UriSpec>("foo://").is_ok());
117/// assert!(iri_reference::<UriSpec>("foo:///").is_ok());
118/// assert!(iri_reference::<UriSpec>("foo:////").is_ok());
119/// assert!(iri_reference::<UriSpec>("foo://///").is_ok());
120/// assert!(iri_reference::<UriSpec>("foo/bar").is_ok());
121/// assert!(iri_reference::<UriSpec>("/foo/bar").is_ok());
122/// assert!(iri_reference::<UriSpec>("//foo/bar").is_ok());
123/// assert!(iri_reference::<UriSpec>("#foo").is_ok());
124/// ```
125///
126/// Some characters and sequences cannot used in an IRI reference.
127///
128/// ```
129/// use iri_string::{spec::UriSpec, validate::iri_reference};
130/// // `<` and `>` cannot directly appear in an IRI reference.
131/// assert!(iri_reference::<UriSpec>("<not allowed>").is_err());
132/// // Broken percent encoding cannot appear in an IRI reference.
133/// assert!(iri_reference::<UriSpec>("%").is_err());
134/// assert!(iri_reference::<UriSpec>("%GG").is_err());
135/// ```
136///
137/// [uri-reference]: https://tools.ietf.org/html/rfc3986#section-4.1
138/// [`RiReferenceStr`]: ../types/struct.RiReferenceStr.html
139/// [`RiReferenceString`]: ../types/struct.RiReferenceString.html
140pub fn iri_reference<S: Spec>(s: &str) -> Result<(), Error> {
141 parser::validate_uri_reference::<S>(s)
142}
143
144/// Validates [absolute IRI][absolute-uri].
145///
146/// This validator corresponds to [`RiAbsoluteStr`] and [`RiAbsoluteString`] types.
147///
148/// # Examples
149///
150/// This type can have an absolute IRI without fragment part.
151///
152/// ```
153/// use iri_string::{spec::UriSpec, validate::absolute_iri};
154/// assert!(absolute_iri::<UriSpec>("https://example.com/foo?bar=baz").is_ok());
155/// assert!(absolute_iri::<UriSpec>("foo:bar").is_ok());
156/// // Scheme `foo` and empty path.
157/// assert!(absolute_iri::<UriSpec>("foo:").is_ok());
158/// // `foo://.../` below are all allowed. See the crate documentation for detail.
159/// assert!(absolute_iri::<UriSpec>("foo:/").is_ok());
160/// assert!(absolute_iri::<UriSpec>("foo://").is_ok());
161/// assert!(absolute_iri::<UriSpec>("foo:///").is_ok());
162/// assert!(absolute_iri::<UriSpec>("foo:////").is_ok());
163/// assert!(absolute_iri::<UriSpec>("foo://///").is_ok());
164///
165/// ```
166///
167/// Relative IRI is not allowed.
168///
169/// ```
170/// use iri_string::{spec::UriSpec, validate::absolute_iri};
171/// // This is relative path.
172/// assert!(absolute_iri::<UriSpec>("foo/bar").is_err());
173/// // `/foo/bar` is an absolute path, but it is authority-relative.
174/// assert!(absolute_iri::<UriSpec>("/foo/bar").is_err());
175/// // `//foo/bar` is termed "network-path reference",
176/// // or usually called "protocol-relative reference".
177/// assert!(absolute_iri::<UriSpec>("//foo/bar").is_err());
178/// // Empty string is not a valid absolute IRI.
179/// assert!(absolute_iri::<UriSpec>("").is_err());
180/// ```
181///
182/// Fragment part (such as trailing `#foo`) is not allowed.
183///
184/// ```
185/// use iri_string::{spec::UriSpec, validate::absolute_iri};
186/// // Fragment part is not allowed.
187/// assert!(absolute_iri::<UriSpec>("https://example.com/foo?bar=baz#qux").is_err());
188/// ```
189///
190/// Some characters and sequences cannot used in an absolute IRI.
191///
192/// ```
193/// use iri_string::{spec::UriSpec, validate::absolute_iri};
194/// // `<` and `>` cannot directly appear in an absolute IRI.
195/// assert!(absolute_iri::<UriSpec>("<not allowed>").is_err());
196/// // Broken percent encoding cannot appear in an absolute IRI.
197/// assert!(absolute_iri::<UriSpec>("%").is_err());
198/// assert!(absolute_iri::<UriSpec>("%GG").is_err());
199/// ```
200///
201/// [absolute-uri]: https://tools.ietf.org/html/rfc3986#section-4.3
202/// [`RiAbsoluteStr`]: ../types/struct.RiAbsoluteStr.html
203/// [`RiAbsoluteString`]: ../types/struct.RiAbsoluteString.html
204pub fn absolute_iri<S: Spec>(s: &str) -> Result<(), Error> {
205 parser::validate_absolute_uri::<S>(s)
206}
207
208/// Validates [relative reference][relative-ref].
209///
210/// This validator corresponds to [`RiRelativeStr`] and [`RiRelativeString`] types.
211///
212/// # Valid values
213///
214/// This type can have a relative IRI reference.
215///
216/// ```
217/// use iri_string::{spec::UriSpec, validate::relative_ref};
218/// assert!(relative_ref::<UriSpec>("foo").is_ok());
219/// assert!(relative_ref::<UriSpec>("foo/bar").is_ok());
220/// assert!(relative_ref::<UriSpec>("/foo").is_ok());
221/// assert!(relative_ref::<UriSpec>("//foo/bar").is_ok());
222/// assert!(relative_ref::<UriSpec>("?foo").is_ok());
223/// assert!(relative_ref::<UriSpec>("#foo").is_ok());
224/// assert!(relative_ref::<UriSpec>("foo/bar?baz#qux").is_ok());
225/// // The first path component can have colon if the path is absolute.
226/// assert!(relative_ref::<UriSpec>("/foo:bar/").is_ok());
227/// // Second or following path components can have colon.
228/// assert!(relative_ref::<UriSpec>("foo/bar://baz/").is_ok());
229/// assert!(relative_ref::<UriSpec>("./foo://bar").is_ok());
230/// ```
231///
232/// Absolute form of a reference is not allowed.
233///
234/// ```
235/// use iri_string::{spec::UriSpec, validate::relative_ref};
236/// assert!(relative_ref::<UriSpec>("https://example.com/").is_err());
237/// // The first path component cannot have colon, if the path is not absolute.
238/// assert!(relative_ref::<UriSpec>("foo:bar").is_err());
239/// assert!(relative_ref::<UriSpec>("foo:").is_err());
240/// assert!(relative_ref::<UriSpec>("foo:/").is_err());
241/// assert!(relative_ref::<UriSpec>("foo://").is_err());
242/// assert!(relative_ref::<UriSpec>("foo:///").is_err());
243/// assert!(relative_ref::<UriSpec>("foo:////").is_err());
244/// assert!(relative_ref::<UriSpec>("foo://///").is_err());
245/// ```
246///
247/// Some characters and sequences cannot used in an IRI reference.
248///
249/// ```
250/// use iri_string::{spec::UriSpec, validate::relative_ref};
251/// // `<` and `>` cannot directly appear in a relative IRI reference.
252/// assert!(relative_ref::<UriSpec>("<not allowed>").is_err());
253/// // Broken percent encoding cannot appear in a relative IRI reference.
254/// assert!(relative_ref::<UriSpec>("%").is_err());
255/// assert!(relative_ref::<UriSpec>("%GG").is_err());
256/// ```
257///
258/// [relative-ref]: https://tools.ietf.org/html/rfc3986#section-4.2
259/// [`RiRelativeStr`]: ../types/struct.RiRelativeStr.html
260/// [`RiRelativeString`]: ../types/struct.RiRelativeString.html
261pub fn relative_ref<S: Spec>(s: &str) -> Result<(), Error> {
262 parser::validate_relative_ref::<S>(s)
263}
264
265/// Validates [IRI path][path].
266///
267/// [path]: https://tools.ietf.org/html/rfc3986#section-3.3
268pub fn path<S: Spec>(s: &str) -> Result<(), Error> {
269 parser::validate_path::<S>(s)
270}
271
272/// Validates [IRI query][query].
273///
274/// This validator corresponds to [`RiQueryStr`] and [`RiQueryString`] types.
275///
276/// Note that the first `?` character in an IRI is not a part of a query.
277/// For example, `https://example.com/?foo#bar` has a query `foo`, **not** `?foo`.
278///
279/// # Examples
280///
281/// This type can have an IRI query.
282/// Note that the IRI `foo://bar/baz?qux#quux` has the query `qux`, **not** `?qux`.
283///
284/// ```
285/// use iri_string::{spec::UriSpec, validate::query};
286/// assert!(query::<UriSpec>("").is_ok());
287/// assert!(query::<UriSpec>("foo").is_ok());
288/// assert!(query::<UriSpec>("foo/bar").is_ok());
289/// assert!(query::<UriSpec>("/foo/bar").is_ok());
290/// assert!(query::<UriSpec>("//foo/bar").is_ok());
291/// assert!(query::<UriSpec>("https://user:pass@example.com:8080").is_ok());
292/// assert!(query::<UriSpec>("https://example.com/").is_ok());
293/// // Question sign `?` can appear in an IRI query.
294/// assert!(query::<UriSpec>("query?again").is_ok());
295/// ```
296///
297/// Some characters and sequences cannot used in a query.
298///
299/// ```
300/// use iri_string::{spec::UriSpec, validate::query};
301/// // `<` and `>` cannot directly appear in an IRI reference.
302/// assert!(query::<UriSpec>("<not allowed>").is_err());
303/// // Broken percent encoding cannot appear in an IRI reference.
304/// assert!(query::<UriSpec>("%").is_err());
305/// assert!(query::<UriSpec>("%GG").is_err());
306/// // Hash sign `#` cannot appear in an IRI query.
307/// assert!(query::<UriSpec>("#hash").is_err());
308/// ```
309///
310/// [query]: https://tools.ietf.org/html/rfc3986#section-3.4
311/// [`RiQueryStr`]: ../types/struct.RiQueryStr.html
312/// [`RiQueryString`]: ../types/struct.RiQueryString.html
313pub fn query<S: Spec>(s: &str) -> Result<(), Error> {
314 parser::validate_query::<S>(s)
315}
316
317/// Validates [IRI fragment][fragment].
318///
319/// This validator corresponds to [`RiFragmentStr`] and [`RiFragmentString`] types.
320///
321/// Note that the first `#` character in an IRI is not a part of a fragment.
322/// For example, `https://example.com/#foo` has a fragment `foo`, **not** `#foo`.
323///
324/// # Examples
325///
326/// This type can have an IRI fragment.
327/// Note that the IRI `foo://bar/baz#qux` has the fragment `qux`, **not** `#qux`.
328///
329/// ```
330/// use iri_string::{spec::UriSpec, validate::fragment};
331/// assert!(fragment::<UriSpec>("").is_ok());
332/// assert!(fragment::<UriSpec>("foo").is_ok());
333/// assert!(fragment::<UriSpec>("foo/bar").is_ok());
334/// assert!(fragment::<UriSpec>("/foo/bar").is_ok());
335/// assert!(fragment::<UriSpec>("//foo/bar").is_ok());
336/// assert!(fragment::<UriSpec>("https://user:pass@example.com:8080").is_ok());
337/// assert!(fragment::<UriSpec>("https://example.com/").is_ok());
338/// ```
339///
340/// Some characters and sequences cannot used in a fragment.
341///
342/// ```
343/// use iri_string::{spec::UriSpec, validate::fragment};
344/// // `<` and `>` cannot directly appear in an IRI reference.
345/// assert!(fragment::<UriSpec>("<not allowed>").is_err());
346/// // Broken percent encoding cannot appear in an IRI reference.
347/// assert!(fragment::<UriSpec>("%").is_err());
348/// assert!(fragment::<UriSpec>("%GG").is_err());
349/// // Hash sign `#` cannot appear in an IRI fragment.
350/// assert!(fragment::<UriSpec>("#hash").is_err());
351/// ```
352///
353/// [fragment]: https://tools.ietf.org/html/rfc3986#section-3.5
354/// [`RiFragmentStr`]: ../types/struct.RiFragmentStr.html
355/// [`RiFragmentString`]: ../types/struct.RiFragmentString.html
356pub fn fragment<S: Spec>(s: &str) -> Result<(), Error> {
357 parser::validate_fragment::<S>(s)
358}