1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//! Fragment string.
use core::convert::TryFrom;
use crate::{
spec::Spec,
validate::{fragment, Error},
};
define_custom_string_slice! {
/// A borrowed slice of an IRI fragment (i.e. after the first `#` character).
///
/// This corresponds to [`ifragment` rule] in [RFC 3987] (and [`fragment` rule] in [RFC 3986]).
/// The rule for `ifragment` is `*( ipchar / "/" / "?" )`.
///
/// # Valid values
///
/// This type can have an IRI fragment.
/// Note that the IRI `foo://bar/baz#qux` has the fragment `qux`, **not** `#qux`.
///
/// ```
/// # use iri_string::types::IriFragmentStr;
/// assert!(IriFragmentStr::new("").is_ok());
/// assert!(IriFragmentStr::new("foo").is_ok());
/// assert!(IriFragmentStr::new("foo/bar").is_ok());
/// assert!(IriFragmentStr::new("/foo/bar").is_ok());
/// assert!(IriFragmentStr::new("//foo/bar").is_ok());
/// assert!(IriFragmentStr::new("https://user:pass@example.com:8080").is_ok());
/// assert!(IriFragmentStr::new("https://example.com/").is_ok());
/// ```
///
/// Some characters and sequences cannot used in a fragment.
///
/// ```
/// # use iri_string::types::IriFragmentStr;
/// // `<` and `>` cannot directly appear in an IRI reference.
/// assert!(IriFragmentStr::new("<not allowed>").is_err());
/// // Broken percent encoding cannot appear in an IRI reference.
/// assert!(IriFragmentStr::new("%").is_err());
/// assert!(IriFragmentStr::new("%GG").is_err());
/// // Hash sign `#` cannot appear in an IRI fragment.
/// assert!(IriFragmentStr::new("#hash").is_err());
/// ```
///
/// [RFC 3986]: https://tools.ietf.org/html/rfc3986
/// [RFC 3987]: https://tools.ietf.org/html/rfc3987
/// [`fragment` rule]: https://tools.ietf.org/html/rfc3986#section-3.5
/// [`ifragment` rule]: https://tools.ietf.org/html/rfc3987#section-2.2
struct RiFragmentStr {
validator = fragment,
expecting_msg = "IRI fragment string",
}
}
#[cfg(feature = "alloc")]
define_custom_string_owned! {
/// An owned string of an IRI fragment (i.e. after the first `#` character).
///
/// This corresponds to [`ifragment` rule] in [RFC 3987] (and [`fragment` rule] in [RFC 3986]).
/// The rule for `absolute-IRI` is `*( ipchar / "/" / "?" )`.
///
/// For details, see the documentation for [`RiFragmentStr`].
///
/// Enabled by `alloc` or `std` feature.
///
/// [RFC 3986]: https://tools.ietf.org/html/rfc3986
/// [RFC 3987]: https://tools.ietf.org/html/rfc3987
/// [`fragment` rule]: https://tools.ietf.org/html/rfc3986#section-3.5
/// [`ifragment` rule]: https://tools.ietf.org/html/rfc3987#section-2.2
/// [`RiFragmentStr`]: struct.RiFragmentStr.html
struct RiFragmentString {
validator = fragment,
slice = RiFragmentStr,
expecting_msg = "IRI fragment string",
}
}
impl<S: Spec> RiFragmentStr<S> {
/// Creates a new `&RiFragmentStr` from the fragment part prefixed by `#`.
///
/// # Examples
///
/// ```
/// # use iri_string::types::IriFragmentStr;
/// assert!(IriFragmentStr::from_prefixed("#").is_ok());
/// assert!(IriFragmentStr::from_prefixed("#foo").is_ok());
/// assert!(IriFragmentStr::from_prefixed("#foo/bar").is_ok());
/// assert!(IriFragmentStr::from_prefixed("#/foo/bar").is_ok());
/// assert!(IriFragmentStr::from_prefixed("#//foo/bar").is_ok());
/// assert!(IriFragmentStr::from_prefixed("#https://user:pass@example.com:8080").is_ok());
/// assert!(IriFragmentStr::from_prefixed("#https://example.com/").is_ok());
///
/// // `<` and `>` cannot directly appear in an IRI.
/// assert!(IriFragmentStr::from_prefixed("#<not allowed>").is_err());
/// // Broken percent encoding cannot appear in an IRI.
/// assert!(IriFragmentStr::new("#%").is_err());
/// assert!(IriFragmentStr::new("#%GG").is_err());
/// // `#` prefix is expected.
/// assert!(IriFragmentStr::from_prefixed("").is_err());
/// assert!(IriFragmentStr::from_prefixed("foo").is_err());
/// // Hash sign `#` cannot appear in an IRI fragment.
/// assert!(IriFragmentStr::from_prefixed("##hash").is_err());
/// ```
pub fn from_prefixed(s: &str) -> Result<&Self, Error> {
if !s.starts_with('#') {
return Err(Error::new());
}
TryFrom::try_from(&s[1..])
}
}