/rust/registry/src/index.crates.io-1949cf8c6b5b557f/sfv-0.14.0/src/key.rs
Line | Count | Source |
1 | | use std::{borrow::Borrow, fmt}; |
2 | | |
3 | | use crate::{ |
4 | | error::{Error, NonEmptyStringError}, |
5 | | utils, |
6 | | }; |
7 | | |
8 | | /// An owned structured field value [key]. |
9 | | /// |
10 | | /// Keys must match the following regular expression: |
11 | | /// |
12 | | /// ```re |
13 | | /// ^[A-Za-z*][A-Za-z*0-9!#$%&'+\-.^_`|~]*$ |
14 | | /// ``` |
15 | | /// |
16 | | /// [key]: <https://httpwg.org/specs/rfc9651.html#key> |
17 | | #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
18 | | pub struct Key(String); |
19 | | |
20 | | /// A borrowed structured field value [key]. |
21 | | /// |
22 | | /// Keys must match the following regular expression: |
23 | | /// |
24 | | /// ```re |
25 | | /// ^[A-Za-z*][A-Za-z*0-9!#$%&'+\-.^_`|~]*$ |
26 | | /// ``` |
27 | | /// |
28 | | /// This type is to [`Key`] as [`str`] is to [`String`]. |
29 | | /// |
30 | | /// [key]: <https://httpwg.org/specs/rfc9651.html#key> |
31 | | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, ref_cast::RefCastCustom)] |
32 | | #[repr(transparent)] |
33 | | pub struct KeyRef(str); |
34 | | |
35 | 1.43M | const fn validate(v: &[u8]) -> Result<(), NonEmptyStringError> { |
36 | 1.43M | if v.is_empty() { |
37 | 0 | return Err(NonEmptyStringError::empty()); |
38 | 1.43M | } |
39 | | |
40 | 1.43M | if !utils::is_allowed_start_key_char(v[0]) { |
41 | 0 | return Err(NonEmptyStringError::invalid_character(0)); |
42 | 1.43M | } |
43 | | |
44 | 1.43M | let mut index = 1; |
45 | | |
46 | 40.3M | while index < v.len() { |
47 | 38.9M | if !utils::is_allowed_inner_key_char(v[index]) { |
48 | 0 | return Err(NonEmptyStringError::invalid_character(index)); |
49 | 38.9M | } |
50 | 38.9M | index += 1; |
51 | | } |
52 | | |
53 | 1.43M | Ok(()) |
54 | 1.43M | } |
55 | | |
56 | | impl KeyRef { |
57 | | #[ref_cast::ref_cast_custom] |
58 | 1.43M | const fn cast(v: &str) -> &Self; |
59 | | |
60 | | /// Creates a `&KeyRef` from a `&str`. |
61 | | /// |
62 | | /// # Errors |
63 | | /// If the input string validation fails. |
64 | | #[allow(clippy::should_implement_trait)] |
65 | 0 | pub fn from_str(v: &str) -> Result<&Self, Error> { |
66 | 0 | validate(v.as_bytes())?; |
67 | 0 | Ok(Self::cast(v)) |
68 | 0 | } |
69 | | |
70 | | // Like `from_str`, but assumes that the contents of the string have already |
71 | | // been validated as a key. |
72 | 1.43M | pub(crate) fn from_validated_str(v: &str) -> &Self { |
73 | 1.43M | debug_assert!(validate(v.as_bytes()).is_ok()); |
74 | 1.43M | Self::cast(v) |
75 | 1.43M | } |
76 | | |
77 | | /// Creates a `&KeyRef`, panicking if the value is invalid. |
78 | | /// |
79 | | /// This method is intended to be called from `const` contexts in which the |
80 | | /// value is known to be valid. Use [`KeyRef::from_str`] for non-panicking |
81 | | /// conversions. |
82 | | /// |
83 | | /// # Errors |
84 | | /// If the input string validation fails. |
85 | | #[must_use] |
86 | 0 | pub const fn constant(v: &str) -> &Self { |
87 | 0 | match validate(v.as_bytes()) { |
88 | 0 | Ok(()) => Self::cast(v), |
89 | 0 | Err(err) => panic!("{}", err.msg()), |
90 | | } |
91 | 0 | } |
92 | | |
93 | | /// Returns the key as a `&str`. |
94 | | #[must_use] |
95 | 4.13k | pub fn as_str(&self) -> &str { |
96 | 4.13k | &self.0 |
97 | 4.13k | } |
98 | | } |
99 | | |
100 | | impl ToOwned for KeyRef { |
101 | | type Owned = Key; |
102 | | |
103 | 1.43M | fn to_owned(&self) -> Key { |
104 | 1.43M | Key(self.0.to_owned()) |
105 | 1.43M | } |
106 | | |
107 | 0 | fn clone_into(&self, target: &mut Key) { |
108 | 0 | self.0.clone_into(&mut target.0); |
109 | 0 | } |
110 | | } |
111 | | |
112 | | impl Borrow<KeyRef> for Key { |
113 | 0 | fn borrow(&self) -> &KeyRef { |
114 | 0 | self |
115 | 0 | } |
116 | | } |
117 | | |
118 | | impl std::ops::Deref for Key { |
119 | | type Target = KeyRef; |
120 | | |
121 | 4.13k | fn deref(&self) -> &KeyRef { |
122 | 4.13k | KeyRef::cast(&self.0) |
123 | 4.13k | } |
124 | | } |
125 | | |
126 | | impl From<Key> for String { |
127 | 0 | fn from(v: Key) -> String { |
128 | 0 | v.0 |
129 | 0 | } |
130 | | } |
131 | | |
132 | | impl TryFrom<String> for Key { |
133 | | type Error = Error; |
134 | | |
135 | 0 | fn try_from(v: String) -> Result<Key, Error> { |
136 | 0 | validate(v.as_bytes())?; |
137 | 0 | Ok(Key(v)) |
138 | 0 | } |
139 | | } |
140 | | |
141 | | impl Key { |
142 | | /// Creates a `Key` from a `String`. |
143 | | /// |
144 | | /// Returns the original value if the conversion failed. |
145 | | /// |
146 | | /// # Errors |
147 | | /// If the input string validation fails. |
148 | 0 | pub fn from_string(v: String) -> Result<Self, (Error, String)> { |
149 | 0 | match validate(v.as_bytes()) { |
150 | 0 | Ok(()) => Ok(Self(v)), |
151 | 0 | Err(err) => Err((err.into(), v)), |
152 | | } |
153 | 0 | } |
154 | | } |
155 | | |
156 | | /// Creates a `&KeyRef`, panicking if the value is invalid. |
157 | | /// |
158 | | /// This is a convenience free function for [`KeyRef::constant`]. |
159 | | /// |
160 | | /// This method is intended to be called from `const` contexts in which the |
161 | | /// value is known to be valid. Use [`KeyRef::from_str`] for non-panicking |
162 | | /// conversions. |
163 | | #[must_use] |
164 | 0 | pub const fn key_ref(v: &str) -> &KeyRef { |
165 | 0 | KeyRef::constant(v) |
166 | 0 | } |
167 | | |
168 | | impl fmt::Display for KeyRef { |
169 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
170 | 0 | f.write_str(self.as_str()) |
171 | 0 | } |
172 | | } |
173 | | |
174 | | impl fmt::Display for Key { |
175 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
176 | 0 | <KeyRef as fmt::Display>::fmt(self, f) |
177 | 0 | } |
178 | | } |
179 | | |
180 | | macro_rules! impl_eq { |
181 | | ($a: ty, $b: ty) => { |
182 | | impl PartialEq<$a> for $b { |
183 | 0 | fn eq(&self, other: &$a) -> bool { |
184 | 0 | <KeyRef as PartialEq>::eq(self, other) |
185 | 0 | } Unexecuted instantiation: <sfv::key::KeyRef as core::cmp::PartialEq<sfv::key::Key>>::eq Unexecuted instantiation: <&sfv::key::KeyRef as core::cmp::PartialEq<sfv::key::Key>>::eq |
186 | | } |
187 | | impl PartialEq<$b> for $a { |
188 | 0 | fn eq(&self, other: &$b) -> bool { |
189 | 0 | <KeyRef as PartialEq>::eq(self, other) |
190 | 0 | } Unexecuted instantiation: <sfv::key::Key as core::cmp::PartialEq<sfv::key::KeyRef>>::eq Unexecuted instantiation: <sfv::key::Key as core::cmp::PartialEq<&sfv::key::KeyRef>>::eq |
191 | | } |
192 | | }; |
193 | | } |
194 | | |
195 | | impl_eq!(Key, KeyRef); |
196 | | impl_eq!(Key, &KeyRef); |
197 | | |
198 | | impl<'a> TryFrom<&'a str> for &'a KeyRef { |
199 | | type Error = Error; |
200 | | |
201 | 0 | fn try_from(v: &'a str) -> Result<&'a KeyRef, Error> { |
202 | 0 | KeyRef::from_str(v) |
203 | 0 | } |
204 | | } |
205 | | |
206 | | impl Borrow<str> for Key { |
207 | 4.13k | fn borrow(&self) -> &str { |
208 | 4.13k | self.as_str() |
209 | 4.13k | } |
210 | | } |
211 | | |
212 | | impl Borrow<str> for KeyRef { |
213 | 0 | fn borrow(&self) -> &str { |
214 | 0 | self.as_str() |
215 | 0 | } |
216 | | } |
217 | | |
218 | | impl AsRef<KeyRef> for Key { |
219 | 0 | fn as_ref(&self) -> &KeyRef { |
220 | 0 | self |
221 | 0 | } |
222 | | } |
223 | | |
224 | | impl AsRef<KeyRef> for KeyRef { |
225 | 0 | fn as_ref(&self) -> &KeyRef { |
226 | 0 | self |
227 | 0 | } |
228 | | } |
229 | | |
230 | | #[cfg(feature = "arbitrary")] |
231 | | impl<'a> arbitrary::Arbitrary<'a> for &'a KeyRef { |
232 | | fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> { |
233 | | KeyRef::from_str(<&str>::arbitrary(u)?).map_err(|_| arbitrary::Error::IncorrectFormat) |
234 | | } |
235 | | |
236 | | fn size_hint(_depth: usize) -> (usize, Option<usize>) { |
237 | | (1, None) |
238 | | } |
239 | | } |
240 | | |
241 | | #[cfg(feature = "arbitrary")] |
242 | | impl<'a> arbitrary::Arbitrary<'a> for Key { |
243 | | fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> { |
244 | | <&KeyRef>::arbitrary(u).map(ToOwned::to_owned) |
245 | | } |
246 | | |
247 | | fn size_hint(_depth: usize) -> (usize, Option<usize>) { |
248 | | (1, None) |
249 | | } |
250 | | } |