iri_string/validate.rs
1//! Validators.
2//!
3//! Validators are functions that receive the string and checks if the entire
4//! string is syntactically valid.
5
6use core::fmt;
7
8#[cfg(feature = "std")]
9use std::error;
10
11use crate::parser::validate as parser;
12use crate::spec::Spec;
13
14/// Resource identifier validation error.
15// Note that this type should implement `Copy` trait.
16// To return additional non-`Copy` data as an error, use wrapper type
17// (as `std::string::FromUtf8Error` contains `std::str::Utf8Error`).
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub struct Error {
20 /// Error kind.
21 kind: ErrorKind,
22}
23
24impl Error {
25 /// Creates a new `Error` from the given error kind.
26 #[inline]
27 #[must_use]
28 pub(crate) fn with_kind(kind: ErrorKind) -> Self {
29 Self { kind }
30 }
31}
32
33impl fmt::Display for Error {
34 #[inline]
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 write!(f, "invalid IRI: {}", self.kind.description())
37 }
38}
39
40#[cfg(feature = "std")]
41impl error::Error for Error {}
42
43/// Error kind.
44///
45/// This type may be reorganized between minor version bumps, so users should
46/// not expect specific error kind (or specific error message) to be returned
47/// for a specific error.
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49#[non_exhaustive]
50pub(crate) enum ErrorKind {
51 /// Invalid scheme.
52 InvalidScheme,
53 /// Invalid userinfo.
54 InvalidUserInfo,
55 /// Invalid host.
56 InvalidHost,
57 /// Invalid `reg-name`.
58 InvalidRegName,
59 /// Invalid port.
60 InvalidPort,
61 /// Invalid path character.
62 InvalidPath,
63 /// Invalid query.
64 InvalidQuery,
65 /// Invalid fragment.
66 InvalidFragment,
67 /// Got an unexpected fragment.
68 UnexpectedFragment,
69 /// Expected a relative IRI but got an absolute IRI.
70 UnexpectedAbsolute,
71 /// Expected an absolute IRI but got a relative IRI.
72 UnexpectedRelative,
73 /// Invalid UTF-8 bytes.
74 InvalidUtf8,
75}
76
77impl ErrorKind {
78 /// Returns the human-friendly description for the error kind.
79 #[must_use]
80 fn description(self) -> &'static str {
81 match self {
82 Self::InvalidScheme => "invalid scheme",
83 Self::InvalidUserInfo => "invalid userinfo",
84 Self::InvalidHost => "invalid host",
85 Self::InvalidRegName => "invalid reg-name",
86 Self::InvalidPort => "invalid port",
87 Self::InvalidPath => "invalid path",
88 Self::InvalidQuery => "invalid query",
89 Self::InvalidFragment => "invalid fragment",
90 Self::UnexpectedFragment => "unexpected fragment",
91 Self::UnexpectedAbsolute => "expected a relative IRI but got an absolute IRI",
92 Self::UnexpectedRelative => "expected an absolute IRI but got a relative IRI",
93 Self::InvalidUtf8 => "invalid utf-8 bytes",
94 }
95 }
96}
97
98/// Validates [IRI][uri].
99///
100/// This validator corresponds to [`RiStr`] and [`RiString`] types.
101///
102/// # Examples
103///
104/// This type can have an IRI (which is absolute, and may have fragment part).
105///
106/// ```
107/// use iri_string::{spec::UriSpec, validate::iri};
108/// assert!(iri::<UriSpec>("https://user:pass@example.com:8080").is_ok());
109/// assert!(iri::<UriSpec>("https://example.com/").is_ok());
110/// assert!(iri::<UriSpec>("https://example.com/foo?bar=baz").is_ok());
111/// assert!(iri::<UriSpec>("https://example.com/foo?bar=baz#qux").is_ok());
112/// assert!(iri::<UriSpec>("foo:bar").is_ok());
113/// assert!(iri::<UriSpec>("foo:").is_ok());
114/// // `foo://.../` below are all allowed. See the crate documentation for detail.
115/// assert!(iri::<UriSpec>("foo:/").is_ok());
116/// assert!(iri::<UriSpec>("foo://").is_ok());
117/// assert!(iri::<UriSpec>("foo:///").is_ok());
118/// assert!(iri::<UriSpec>("foo:////").is_ok());
119/// assert!(iri::<UriSpec>("foo://///").is_ok());
120/// ```
121///
122/// Relative IRI reference is not allowed.
123///
124/// ```
125/// use iri_string::{spec::UriSpec, validate::iri};
126/// // This is relative path.
127/// assert!(iri::<UriSpec>("foo/bar").is_err());
128/// // `/foo/bar` is an absolute path, but it is authority-relative.
129/// assert!(iri::<UriSpec>("/foo/bar").is_err());
130/// // `//foo/bar` is termed "network-path reference",
131/// // or usually called "protocol-relative reference".
132/// assert!(iri::<UriSpec>("//foo/bar").is_err());
133/// // Same-document reference is relative.
134/// assert!(iri::<UriSpec>("#foo").is_err());
135/// // Empty string is not a valid absolute IRI.
136/// assert!(iri::<UriSpec>("").is_err());
137/// ```
138///
139/// Some characters and sequences cannot used in an IRI.
140///
141/// ```
142/// use iri_string::{spec::UriSpec, validate::iri};
143/// // `<` and `>` cannot directly appear in an IRI.
144/// assert!(iri::<UriSpec>("<not allowed>").is_err());
145/// // Broken percent encoding cannot appear in an IRI.
146/// assert!(iri::<UriSpec>("%").is_err());
147/// assert!(iri::<UriSpec>("%GG").is_err());
148/// ```
149///
150/// [uri]: https://www.rfc-editor.org/rfc/rfc3986.html#section-3
151/// [`RiStr`]: ../types/struct.RiStr.html
152/// [`RiString`]: ../types/struct.RiString.html
153pub fn iri<S: Spec>(s: &str) -> Result<(), Error> {
154 parser::validate_uri::<S>(s)
155}
156
157/// Validates [IRI reference][uri-reference].
158///
159/// This validator corresponds to [`RiReferenceStr`] and [`RiReferenceString`] types.
160///
161/// # Examples
162///
163/// This type can have an IRI reference (which can be absolute or relative).
164///
165/// ```
166/// use iri_string::{spec::UriSpec, validate::iri_reference};
167/// assert!(iri_reference::<UriSpec>("https://user:pass@example.com:8080").is_ok());
168/// assert!(iri_reference::<UriSpec>("https://example.com/").is_ok());
169/// assert!(iri_reference::<UriSpec>("https://example.com/foo?bar=baz").is_ok());
170/// assert!(iri_reference::<UriSpec>("https://example.com/foo?bar=baz#qux").is_ok());
171/// assert!(iri_reference::<UriSpec>("foo:bar").is_ok());
172/// assert!(iri_reference::<UriSpec>("foo:").is_ok());
173/// // `foo://.../` below are all allowed. See the crate documentation for detail.
174/// assert!(iri_reference::<UriSpec>("foo:/").is_ok());
175/// assert!(iri_reference::<UriSpec>("foo://").is_ok());
176/// assert!(iri_reference::<UriSpec>("foo:///").is_ok());
177/// assert!(iri_reference::<UriSpec>("foo:////").is_ok());
178/// assert!(iri_reference::<UriSpec>("foo://///").is_ok());
179/// assert!(iri_reference::<UriSpec>("foo/bar").is_ok());
180/// assert!(iri_reference::<UriSpec>("/foo/bar").is_ok());
181/// assert!(iri_reference::<UriSpec>("//foo/bar").is_ok());
182/// assert!(iri_reference::<UriSpec>("#foo").is_ok());
183/// ```
184///
185/// Some characters and sequences cannot used in an IRI reference.
186///
187/// ```
188/// use iri_string::{spec::UriSpec, validate::iri_reference};
189/// // `<` and `>` cannot directly appear in an IRI reference.
190/// assert!(iri_reference::<UriSpec>("<not allowed>").is_err());
191/// // Broken percent encoding cannot appear in an IRI reference.
192/// assert!(iri_reference::<UriSpec>("%").is_err());
193/// assert!(iri_reference::<UriSpec>("%GG").is_err());
194/// ```
195///
196/// [uri-reference]: https://www.rfc-editor.org/rfc/rfc3986.html#section-4.1
197/// [`RiReferenceStr`]: ../types/struct.RiReferenceStr.html
198/// [`RiReferenceString`]: ../types/struct.RiReferenceString.html
199pub fn iri_reference<S: Spec>(s: &str) -> Result<(), Error> {
200 parser::validate_uri_reference::<S>(s)
201}
202
203/// Validates [absolute IRI][absolute-uri].
204///
205/// This validator corresponds to [`RiAbsoluteStr`] and [`RiAbsoluteString`] types.
206///
207/// # Examples
208///
209/// This type can have an absolute IRI without fragment part.
210///
211/// ```
212/// use iri_string::{spec::UriSpec, validate::absolute_iri};
213/// assert!(absolute_iri::<UriSpec>("https://example.com/foo?bar=baz").is_ok());
214/// assert!(absolute_iri::<UriSpec>("foo:bar").is_ok());
215/// // Scheme `foo` and empty path.
216/// assert!(absolute_iri::<UriSpec>("foo:").is_ok());
217/// // `foo://.../` below are all allowed. See the crate documentation for detail.
218/// assert!(absolute_iri::<UriSpec>("foo:/").is_ok());
219/// assert!(absolute_iri::<UriSpec>("foo://").is_ok());
220/// assert!(absolute_iri::<UriSpec>("foo:///").is_ok());
221/// assert!(absolute_iri::<UriSpec>("foo:////").is_ok());
222/// assert!(absolute_iri::<UriSpec>("foo://///").is_ok());
223///
224/// ```
225///
226/// Relative IRI is not allowed.
227///
228/// ```
229/// use iri_string::{spec::UriSpec, validate::absolute_iri};
230/// // This is relative path.
231/// assert!(absolute_iri::<UriSpec>("foo/bar").is_err());
232/// // `/foo/bar` is an absolute path, but it is authority-relative.
233/// assert!(absolute_iri::<UriSpec>("/foo/bar").is_err());
234/// // `//foo/bar` is termed "network-path reference",
235/// // or usually called "protocol-relative reference".
236/// assert!(absolute_iri::<UriSpec>("//foo/bar").is_err());
237/// // Empty string is not a valid absolute IRI.
238/// assert!(absolute_iri::<UriSpec>("").is_err());
239/// ```
240///
241/// Fragment part (such as trailing `#foo`) is not allowed.
242///
243/// ```
244/// use iri_string::{spec::UriSpec, validate::absolute_iri};
245/// // Fragment part is not allowed.
246/// assert!(absolute_iri::<UriSpec>("https://example.com/foo?bar=baz#qux").is_err());
247/// ```
248///
249/// Some characters and sequences cannot used in an absolute IRI.
250///
251/// ```
252/// use iri_string::{spec::UriSpec, validate::absolute_iri};
253/// // `<` and `>` cannot directly appear in an absolute IRI.
254/// assert!(absolute_iri::<UriSpec>("<not allowed>").is_err());
255/// // Broken percent encoding cannot appear in an absolute IRI.
256/// assert!(absolute_iri::<UriSpec>("%").is_err());
257/// assert!(absolute_iri::<UriSpec>("%GG").is_err());
258/// ```
259///
260/// [absolute-uri]: https://www.rfc-editor.org/rfc/rfc3986.html#section-4.3
261/// [`RiAbsoluteStr`]: ../types/struct.RiAbsoluteStr.html
262/// [`RiAbsoluteString`]: ../types/struct.RiAbsoluteString.html
263pub fn absolute_iri<S: Spec>(s: &str) -> Result<(), Error> {
264 parser::validate_absolute_uri::<S>(s)
265}
266
267/// Validates [relative reference][relative-ref].
268///
269/// This validator corresponds to [`RiRelativeStr`] and [`RiRelativeString`] types.
270///
271/// # Valid values
272///
273/// This type can have a relative IRI reference.
274///
275/// ```
276/// use iri_string::{spec::UriSpec, validate::relative_ref};
277/// assert!(relative_ref::<UriSpec>("foo").is_ok());
278/// assert!(relative_ref::<UriSpec>("foo/bar").is_ok());
279/// assert!(relative_ref::<UriSpec>("/foo").is_ok());
280/// assert!(relative_ref::<UriSpec>("//foo/bar").is_ok());
281/// assert!(relative_ref::<UriSpec>("?foo").is_ok());
282/// assert!(relative_ref::<UriSpec>("#foo").is_ok());
283/// assert!(relative_ref::<UriSpec>("foo/bar?baz#qux").is_ok());
284/// // The first path component can have colon if the path is absolute.
285/// assert!(relative_ref::<UriSpec>("/foo:bar/").is_ok());
286/// // Second or following path components can have colon.
287/// assert!(relative_ref::<UriSpec>("foo/bar://baz/").is_ok());
288/// assert!(relative_ref::<UriSpec>("./foo://bar").is_ok());
289/// ```
290///
291/// Absolute form of a reference is not allowed.
292///
293/// ```
294/// use iri_string::{spec::UriSpec, validate::relative_ref};
295/// assert!(relative_ref::<UriSpec>("https://example.com/").is_err());
296/// // The first path component cannot have colon, if the path is not absolute.
297/// assert!(relative_ref::<UriSpec>("foo:bar").is_err());
298/// assert!(relative_ref::<UriSpec>("foo:").is_err());
299/// assert!(relative_ref::<UriSpec>("foo:/").is_err());
300/// assert!(relative_ref::<UriSpec>("foo://").is_err());
301/// assert!(relative_ref::<UriSpec>("foo:///").is_err());
302/// assert!(relative_ref::<UriSpec>("foo:////").is_err());
303/// assert!(relative_ref::<UriSpec>("foo://///").is_err());
304/// ```
305///
306/// Some characters and sequences cannot used in an IRI reference.
307///
308/// ```
309/// use iri_string::{spec::UriSpec, validate::relative_ref};
310/// // `<` and `>` cannot directly appear in a relative IRI reference.
311/// assert!(relative_ref::<UriSpec>("<not allowed>").is_err());
312/// // Broken percent encoding cannot appear in a relative IRI reference.
313/// assert!(relative_ref::<UriSpec>("%").is_err());
314/// assert!(relative_ref::<UriSpec>("%GG").is_err());
315/// ```
316///
317/// [relative-ref]: https://www.rfc-editor.org/rfc/rfc3986.html#section-4.2
318/// [`RiRelativeStr`]: ../types/struct.RiRelativeStr.html
319/// [`RiRelativeString`]: ../types/struct.RiRelativeString.html
320pub fn relative_ref<S: Spec>(s: &str) -> Result<(), Error> {
321 parser::validate_relative_ref::<S>(s)
322}
323
324/// Validates [IRI scheme][scheme].
325///
326/// Note that this function does not accept a trailing colon.
327///
328/// Also note that the syntax of the scheme is common between RFC 3986 (URIs)
329/// and RFC 3987 (IRIs).
330///
331/// # Examples
332///
333/// ```
334/// use iri_string::validate::scheme;
335/// assert!(scheme("https").is_ok());
336/// assert!(scheme("file").is_ok());
337/// assert!(scheme("git+ssh").is_ok());
338///
339/// // Colon is syntactically not part of the scheme.
340/// assert!(scheme("colon:").is_err());
341/// // Scheme cannot be empty.
342/// assert!(scheme("").is_err());
343/// // The first character should be alphabetic character.
344/// assert!(scheme("0abc").is_err());
345/// assert!(scheme("+a").is_err());
346/// assert!(scheme("-a").is_err());
347/// ```
348///
349/// [scheme]: https://www.rfc-editor.org/rfc/rfc3986.html#section-3.1
350pub fn scheme(s: &str) -> Result<(), Error> {
351 parser::validate_scheme(s)
352}
353
354/// Validates [IRI authority][authority].
355///
356/// # Examples
357///
358/// ```
359/// use iri_string::{spec::UriSpec, validate::authority};
360/// assert!(authority::<UriSpec>("example.com").is_ok());
361/// assert!(authority::<UriSpec>("subdomain.example.com").is_ok());
362/// assert!(authority::<UriSpec>("no-period").is_ok());
363/// // Though strongly discouraged, this percent-encoded reg-name with
364/// // non-UTF-8 bytes is considered syntactically valid.
365/// assert!(authority::<UriSpec>("non-%99-utf-8").is_ok());
366/// // Empty authority is valid. Remember `file:///` has empty authority.
367/// assert!(authority::<UriSpec>("").is_ok());
368/// assert!(authority::<UriSpec>("127.0.0.1:8080").is_ok());
369/// assert!(authority::<UriSpec>("[::127.0.0.1]:8088").is_ok());
370/// // URI/IRI syntax itself does not have limit on the port number.
371/// assert!(authority::<UriSpec>("[::1]:9999999999").is_ok());
372/// // Syntax for future versions of IP addresses.
373/// assert!(authority::<UriSpec>("[v89ab.1+2,3(4)5&6]").is_ok());
374/// assert!(authority::<UriSpec>("user:password@host").is_ok());
375/// assert!(authority::<UriSpec>("co%3Alon:at%40sign@host:8888").is_ok());
376/// // Percent-encoded non-UTF8 (or even non-ASCII) bytes are valid.
377/// // Users are responsible to validate or reject such unusual input if needed.
378/// assert!(authority::<UriSpec>("not-a-%80-utf8@host").is_ok());
379///
380/// // Invalid percent encodings.
381/// assert!(authority::<UriSpec>("invalid%GGescape@host").is_err());
382/// // Invalid characters.
383/// assert!(authority::<UriSpec>("foo@bar@host").is_err());
384/// assert!(authority::<UriSpec>("slash/is-not-allowed").is_err());
385/// ```
386///
387/// [authority]: https://www.rfc-editor.org/rfc/rfc3986.html#section-3.2
388pub fn authority<S: Spec>(s: &str) -> Result<(), Error> {
389 parser::validate_authority::<S>(s)
390}
391
392/// Validates [IRI host][host].
393///
394/// # Examples
395///
396/// ```
397/// use iri_string::{spec::UriSpec, validate::host};
398/// assert!(host::<UriSpec>("example.com").is_ok());
399/// assert!(host::<UriSpec>("subdomain.example.com").is_ok());
400/// assert!(host::<UriSpec>("no-period").is_ok());
401/// // Though strongly discouraged, this percent-encoded reg-name with
402/// // non-UTF-8 bytes is considered syntactically valid.
403/// assert!(host::<UriSpec>("non-%99-utf-8").is_ok());
404/// // Empty host is valid. Remember `file:///` has empty authority (and empty host).
405/// assert!(host::<UriSpec>("").is_ok());
406/// assert!(host::<UriSpec>("127.0.0.1").is_ok());
407/// assert!(host::<UriSpec>("[::1]").is_ok());
408/// assert!(host::<UriSpec>("[::127.0.0.1]").is_ok());
409/// // Syntax for future versions of IP addresses.
410/// assert!(host::<UriSpec>("[v89ab.1+2,3(4)5&6]").is_ok());
411///
412/// // `port` is not a part of the host.
413/// assert!(host::<UriSpec>("host:8080").is_err());
414/// // `userinfo` is not a part of the host.
415/// assert!(host::<UriSpec>("user:password@host").is_err());
416/// ```
417///
418/// [host]: https://www.rfc-editor.org/rfc/rfc3986.html#section-3.2.2
419pub fn host<S: Spec>(s: &str) -> Result<(), Error> {
420 parser::validate_host::<S>(s)
421}
422
423/// Validates [reg-name].
424///
425/// # Examples
426///
427/// ```
428/// use iri_string::{spec::UriSpec, validate::reg_name};
429/// assert!(reg_name::<UriSpec>("example.com").is_ok());
430/// assert!(reg_name::<UriSpec>("subdomain.example.com").is_ok());
431/// assert!(reg_name::<UriSpec>("no-period").is_ok());
432/// // Though strongly discouraged, this percent-encoded reg-name with
433/// // non-UTF-8 bytes is considered syntactically valid.
434/// assert!(reg_name::<UriSpec>("non-%99-utf-8").is_ok());
435/// // Empty host is valid. Remember `file:///` has empty authority (and empty host).
436/// assert!(reg_name::<UriSpec>("").is_ok());
437///
438/// // Even if this looks similar to `IPv4address`, it's not,
439/// // and this matches `reg-name` rule.
440/// assert!(reg_name::<UriSpec>("127.0.0.256").is_ok());
441///
442/// // IP addresses are not a `reg-name`.
443/// assert!(reg_name::<UriSpec>("127.0.0.1").is_err());
444/// assert!(reg_name::<UriSpec>("[::1]").is_err());
445/// assert!(reg_name::<UriSpec>("[::127.0.0.1]").is_err());
446/// // Syntax for future versions of IP addresses.
447/// assert!(reg_name::<UriSpec>("[v89ab.1+2,3(4)5&6]").is_err());
448///
449/// // `port` is not a part of the host.
450/// assert!(reg_name::<UriSpec>("host:8080").is_err());
451/// // `userinfo` is not a part of the host.
452/// assert!(reg_name::<UriSpec>("user:password@host").is_err());
453/// ```
454///
455/// [reg-name]: https://www.rfc-editor.org/rfc/rfc3986.html#page-21
456pub fn reg_name<S: Spec>(s: &str) -> Result<(), Error> {
457 parser::validate_reg_name::<S>(s)
458}
459
460/// Validates [IRI port][port].
461///
462/// Note that the syntax of the port is common between RFC 3986 (URIs) and
463/// RFC 3987 (IRIs).
464///
465/// Also note that this function does not accept a leading colon.
466///
467/// [host]: https://www.rfc-editor.org/rfc/rfc3986.html#section-3.2.3
468///
469/// # Examples
470///
471/// ```
472/// use iri_string::validate::port;
473/// assert!(port("0").is_ok());
474/// assert!(port("8080").is_ok());
475/// assert!(port("0000080").is_ok());
476/// // URI/IRI syntax itself does not have limit on the port number.
477/// assert!(port("999999999").is_ok());
478///
479/// // The leading colon is not a part of the `port`.
480/// assert!(port(":443").is_err());
481/// ```
482pub fn port(s: &str) -> Result<(), Error> {
483 if s.bytes().all(|b| b.is_ascii_digit()) {
484 Ok(())
485 } else {
486 Err(Error::with_kind(ErrorKind::InvalidPort))
487 }
488}
489
490/// Validates [IRI userinfo][userinfo].
491///
492/// # Examples
493///
494/// ```
495/// use iri_string::{spec::UriSpec, validate::userinfo};
496/// assert!(userinfo::<UriSpec>("user").is_ok());
497/// assert!(userinfo::<UriSpec>("user:password").is_ok());
498/// assert!(userinfo::<UriSpec>("non-%99-utf-8").is_ok());
499/// // Special characters can be included if they are percent-encoded.
500/// assert!(userinfo::<UriSpec>("co%3Alon:at%40sign").is_ok());
501///
502/// // The trailing atsign is not a part of the userinfo.
503/// assert!(userinfo::<UriSpec>("user:password@").is_err());
504/// // Invalid characters.
505/// assert!(userinfo::<UriSpec>("foo@bar").is_err());
506/// assert!(userinfo::<UriSpec>("slash/is-not-allowed").is_err());
507/// ```
508///
509/// [authority]: https://www.rfc-editor.org/rfc/rfc3986.html#section-3.2.1
510pub fn userinfo<S: Spec>(s: &str) -> Result<(), Error> {
511 parser::validate_userinfo::<S>(s)
512}
513
514/// Validates [IRI path][path].
515///
516/// # Examples
517///
518/// ```
519/// use iri_string::{spec::UriSpec, validate::path};
520/// assert!(path::<UriSpec>("").is_ok());
521/// assert!(path::<UriSpec>("foo/bar").is_ok());
522/// assert!(path::<UriSpec>("foo/bar/").is_ok());
523/// assert!(path::<UriSpec>("/foo/bar").is_ok());
524/// assert!(path::<UriSpec>("non-%99-utf-8").is_ok());
525/// // Be careful! This is completely valid (absolute) path, but may be confused
526/// // with an protocol-relative URI, with the authority `foo` and the path `/bar`.
527/// assert!(path::<UriSpec>("//foo/bar").is_ok());
528/// // Be careful! This is completely valid (relative) path, but may be confused
529/// // with an absolute URI, with the scheme `foo` and the path `bar`.
530/// assert!(path::<UriSpec>("foo:bar").is_ok());
531///
532/// // Invalid characters.
533/// assert!(path::<UriSpec>("foo?bar").is_err());
534/// assert!(path::<UriSpec>("foo#bar").is_err());
535/// ```
536///
537/// [path]: https://www.rfc-editor.org/rfc/rfc3986.html#section-3.3
538pub fn path<S: Spec>(s: &str) -> Result<(), Error> {
539 parser::validate_path::<S>(s)
540}
541
542/// Validates [IRI path segment][segment].
543///
544/// # Examples
545///
546/// ```
547/// use iri_string::{spec::UriSpec, validate::path_segment};
548/// assert!(path_segment::<UriSpec>("").is_ok());
549/// assert!(path_segment::<UriSpec>("escaped-%2F-slash").is_ok());
550/// assert!(path_segment::<UriSpec>("non-%99-utf-8").is_ok());
551///
552/// // A path segment itself cannot contain an unescaped slash.
553/// assert!(path_segment::<UriSpec>("foo/bar").is_err());
554/// ```
555///
556/// [segment]: https://www.rfc-editor.org/rfc/rfc3986.html#section-3.3
557pub fn path_segment<S: Spec>(s: &str) -> Result<(), Error> {
558 parser::validate_path_segment::<S>(s)
559}
560
561/// Validates [IRI query][query].
562///
563/// This validator corresponds to [`RiQueryStr`] and [`RiQueryString`] types.
564///
565/// Note that the first `?` character in an IRI is not a part of a query.
566/// For example, `https://example.com/?foo#bar` has a query `foo`, **not** `?foo`.
567///
568/// # Examples
569///
570/// This type can have an IRI query.
571/// Note that the IRI `foo://bar/baz?qux#quux` has the query `qux`, **not** `?qux`.
572///
573/// ```
574/// use iri_string::{spec::UriSpec, validate::query};
575/// assert!(query::<UriSpec>("").is_ok());
576/// assert!(query::<UriSpec>("foo").is_ok());
577/// assert!(query::<UriSpec>("foo/bar").is_ok());
578/// assert!(query::<UriSpec>("/foo/bar").is_ok());
579/// assert!(query::<UriSpec>("//foo/bar").is_ok());
580/// assert!(query::<UriSpec>("https://user:pass@example.com:8080").is_ok());
581/// assert!(query::<UriSpec>("https://example.com/").is_ok());
582/// // Question sign `?` can appear in an IRI query.
583/// assert!(query::<UriSpec>("query?again").is_ok());
584/// ```
585///
586/// Some characters and sequences cannot used in a query.
587///
588/// ```
589/// use iri_string::{spec::UriSpec, validate::query};
590/// // `<` and `>` cannot directly appear in an IRI reference.
591/// assert!(query::<UriSpec>("<not allowed>").is_err());
592/// // Broken percent encoding cannot appear in an IRI reference.
593/// assert!(query::<UriSpec>("%").is_err());
594/// assert!(query::<UriSpec>("%GG").is_err());
595/// // Hash sign `#` cannot appear in an IRI query.
596/// assert!(query::<UriSpec>("#hash").is_err());
597/// ```
598///
599/// [query]: https://www.rfc-editor.org/rfc/rfc3986.html#section-3.4
600/// [`RiQueryStr`]: ../types/struct.RiQueryStr.html
601/// [`RiQueryString`]: ../types/struct.RiQueryString.html
602pub fn query<S: Spec>(s: &str) -> Result<(), Error> {
603 parser::validate_query::<S>(s)
604}
605
606/// Validates [IRI fragment][fragment].
607///
608/// This validator corresponds to [`RiFragmentStr`] and [`RiFragmentString`] types.
609///
610/// Note that the first `#` character in an IRI is not a part of a fragment.
611/// For example, `https://example.com/#foo` has a fragment `foo`, **not** `#foo`.
612///
613/// # Examples
614///
615/// This type can have an IRI fragment.
616/// Note that the IRI `foo://bar/baz#qux` has the fragment `qux`, **not** `#qux`.
617///
618/// ```
619/// use iri_string::{spec::UriSpec, validate::fragment};
620/// assert!(fragment::<UriSpec>("").is_ok());
621/// assert!(fragment::<UriSpec>("foo").is_ok());
622/// assert!(fragment::<UriSpec>("foo/bar").is_ok());
623/// assert!(fragment::<UriSpec>("/foo/bar").is_ok());
624/// assert!(fragment::<UriSpec>("//foo/bar").is_ok());
625/// assert!(fragment::<UriSpec>("https://user:pass@example.com:8080").is_ok());
626/// assert!(fragment::<UriSpec>("https://example.com/").is_ok());
627/// ```
628///
629/// Some characters and sequences cannot used in a fragment.
630///
631/// ```
632/// use iri_string::{spec::UriSpec, validate::fragment};
633/// // `<` and `>` cannot directly appear in an IRI reference.
634/// assert!(fragment::<UriSpec>("<not allowed>").is_err());
635/// // Broken percent encoding cannot appear in an IRI reference.
636/// assert!(fragment::<UriSpec>("%").is_err());
637/// assert!(fragment::<UriSpec>("%GG").is_err());
638/// // Hash sign `#` cannot appear in an IRI fragment.
639/// assert!(fragment::<UriSpec>("#hash").is_err());
640/// ```
641///
642/// [fragment]: https://www.rfc-editor.org/rfc/rfc3986.html#section-3.5
643/// [`RiFragmentStr`]: ../types/struct.RiFragmentStr.html
644/// [`RiFragmentString`]: ../types/struct.RiFragmentString.html
645pub fn fragment<S: Spec>(s: &str) -> Result<(), Error> {
646 parser::validate_fragment::<S>(s)
647}