Coverage Report

Created: 2025-12-31 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}