1use crate::{cow::Cow, IntoLabels, Label, SharedString};
2use rapidhash::v3::{rapidhash_v3_nano_inline, RapidSecrets};
3use std::{
4 borrow::Borrow,
5 cmp, fmt,
6 hash::{Hash, Hasher},
7 slice::Iter,
8};
9
10const NO_LABELS: [Label; 0] = [];
11
12#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
14pub struct KeyName(SharedString);
15
16impl KeyName {
17 pub const fn from_const_str(name: &'static str) -> Self {
19 KeyName(SharedString::const_str(name))
20 }
21
22 pub const fn as_str(&self) -> &str {
24 self.0.as_const_str()
25 }
26
27 pub fn into_inner(self) -> SharedString {
29 self.0
30 }
31
32 pub fn to_retained(&self) -> Self {
38 KeyName(self.0.to_retained())
39 }
40}
41
42impl<T> From<T> for KeyName
43where
44 T: Into<SharedString>,
45{
46 fn from(name: T) -> Self {
47 KeyName(name.into())
48 }
49}
50
51impl Borrow<str> for KeyName {
52 fn borrow(&self) -> &str {
53 self.0.borrow()
54 }
55}
56
57impl From<KeyName> for std::borrow::Cow<'static, str> {
58 fn from(name: KeyName) -> Self {
59 name.0.into()
60 }
61}
62
63#[derive(Debug, Clone)]
80pub struct Key {
81 name: KeyName,
82 labels: Cow<'static, [Label]>,
83 hash: u64,
84}
85
86impl Key {
87 pub fn from_name<N>(name: N) -> Self
89 where
90 N: Into<KeyName>,
91 {
92 let name = name.into();
93 let labels = Cow::from_owned(Vec::new());
94
95 Self::builder(name, labels)
96 }
97
98 pub fn from_parts<N, L>(name: N, labels: L) -> Self
100 where
101 N: Into<KeyName>,
102 L: IntoLabels,
103 {
104 let name = name.into();
105 let labels = Cow::from_owned(labels.into_labels());
106
107 Self::builder(name, labels)
108 }
109
110 pub fn from_static_labels<N>(name: N, labels: &'static [Label]) -> Self
112 where
113 N: Into<KeyName>,
114 {
115 Self::builder(name.into(), Cow::const_slice(labels))
116 }
117
118 pub const fn from_static_name(name: &'static str) -> Self {
122 Self::from_static_parts(name, &NO_LABELS)
123 }
124
125 pub const fn from_static_parts(name: &'static str, labels: &'static [Label]) -> Self {
129 Self::builder(KeyName::from_const_str(name), Cow::const_slice(labels))
130 }
131
132 const fn builder(name: KeyName, labels: Cow<'static, [Label]>) -> Self {
133 let hash = generate_key_hash(&name, &labels);
134 Self { name, labels, hash }
135 }
136
137 pub fn name(&self) -> &str {
139 self.name.0.as_ref()
140 }
141
142 pub fn name_shared(&self) -> KeyName {
144 self.name.clone()
145 }
146
147 pub fn labels(&self) -> Iter<'_, Label> {
149 self.labels.iter()
150 }
151
152 pub fn into_parts(self) -> (KeyName, Vec<Label>) {
154 (self.name, self.labels.into_owned())
155 }
156
157 pub fn to_retained(&self) -> Self {
163 Self { name: self.name.to_retained(), labels: self.labels.to_retained(), hash: self.hash }
164 }
165
166 pub fn with_extra_labels(&self, extra_labels: Vec<Label>) -> Self {
168 if extra_labels.is_empty() {
169 return self.clone();
170 }
171
172 let name = self.name.clone();
173 let mut labels = self.labels.clone().into_owned();
174 labels.extend(extra_labels);
175
176 Self::builder(name, labels.into())
177 }
178
179 #[inline]
181 pub const fn get_hash(&self) -> u64 {
182 self.hash
183 }
184}
185
186#[inline]
188const fn generate_key_hash(name: &KeyName, labels: &Cow<'static, [Label]>) -> u64 {
189 const SECRETS: RapidSecrets = RapidSecrets::seed_cpp(0);
197
198 let mut hash = hash_bytes(name.0.as_const_str().as_bytes(), &SECRETS);
202
203 let mut i = 0;
207 let labels = labels.as_const_slice();
208 while i < labels.len() {
209 let label_hash = hash_label(&labels[i]);
210 hash = hash.wrapping_add(label_hash);
211 i += 1;
212 }
213
214 hash
215}
216
217#[inline(always)]
219const fn hash_bytes(slice: &[u8], secrets: &RapidSecrets) -> u64 {
220 rapidhash_v3_nano_inline::<false, false>(slice, secrets)
224}
225
226#[inline(always)]
228const fn hash_label(Label(key, value): &Label) -> u64 {
229 const KEY: RapidSecrets = RapidSecrets::seed_cpp(1);
232 const VALUE: RapidSecrets = RapidSecrets::seed_cpp(2);
233
234 let key = hash_bytes(key.as_const_str().as_bytes(), &KEY);
235 let value = hash_bytes(value.as_const_str().as_bytes(), &VALUE);
236
237 key ^ value
238}
239
240impl PartialEq for Key {
241 fn eq(&self, other: &Self) -> bool {
242 if self.hash != other.hash {
243 return false;
244 }
245 if self.name != other.name {
246 return false;
247 }
248 if self.labels.len() != other.labels.len() {
249 return false;
250 }
251 match self.labels.len() {
252 0 => true,
253 1 => self.labels[0] == other.labels[0],
254 2 => {
255 if self.labels[0] == other.labels[0] {
256 self.labels[1] == other.labels[1]
257 } else if self.labels[0] == other.labels[1] {
258 self.labels[1] == other.labels[0]
259 } else {
260 false
261 }
262 }
263 n if n < 8 => {
264 let mut labels_sort_map: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
265 labels_sort_map[..n].sort_by_key(|i| self.labels[*i as usize].key());
266 let mut his_labels_sort_map: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
267 his_labels_sort_map[..n].sort_by_key(|i| other.labels[*i as usize].key());
268 for i in 0..n {
269 if self.labels[labels_sort_map[i] as usize]
270 != other.labels[his_labels_sort_map[i] as usize]
271 {
272 return false;
273 }
274 }
275 true
276 }
277 n => {
278 let mut labels_sort_map: Vec<usize> = (0..n).collect();
279 labels_sort_map.sort_by_key(|i| self.labels[*i].key());
280 let mut his_labels_sort_map: Vec<usize> = (0..n).collect();
281 his_labels_sort_map.sort_by_key(|i| other.labels[*i].key());
282 for i in 0..n {
283 if self.labels[labels_sort_map[i]] != other.labels[his_labels_sort_map[i]] {
284 return false;
285 }
286 }
287 true
288 }
289 }
290 }
291}
292
293impl Eq for Key {}
294
295impl PartialOrd for Key {
296 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
297 Some(self.cmp(other))
298 }
299}
300
301impl Ord for Key {
302 fn cmp(&self, other: &Self) -> cmp::Ordering {
303 match (&self.name, self.labels.len()).cmp(&(&other.name, other.labels.len())) {
304 cmp::Ordering::Less => return cmp::Ordering::Less,
305 cmp::Ordering::Equal => {}
306 cmp::Ordering::Greater => return cmp::Ordering::Greater,
307 }
308 match self.labels.len() {
309 0 => cmp::Ordering::Equal,
310 1 => self.labels[0].cmp(&other.labels[0]),
311 n if n < 8 => {
312 let mut labels_sort_map: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
313 labels_sort_map[..n].sort_by_key(|i| self.labels[*i as usize].key());
314 let mut his_labels_sort_map: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
315 his_labels_sort_map[..n].sort_by_key(|i| other.labels[*i as usize].key());
316 for i in 0..n {
317 match self.labels[labels_sort_map[i] as usize]
318 .cmp(&other.labels[his_labels_sort_map[i] as usize])
319 {
320 cmp::Ordering::Less => return cmp::Ordering::Less,
321 cmp::Ordering::Equal => {}
322 cmp::Ordering::Greater => return cmp::Ordering::Greater,
323 }
324 }
325 cmp::Ordering::Equal
326 }
327 n => {
328 let mut labels_sort_map: Vec<usize> = (0..n).collect();
329 labels_sort_map.sort_by_key(|i| self.labels[*i].key());
330 let mut his_labels_sort_map: Vec<usize> = (0..n).collect();
331 his_labels_sort_map.sort_by_key(|i| other.labels[*i].key());
332 for i in 0..n {
333 match self.labels[labels_sort_map[i]].cmp(&other.labels[his_labels_sort_map[i]])
334 {
335 cmp::Ordering::Less => return cmp::Ordering::Less,
336 cmp::Ordering::Equal => {}
337 cmp::Ordering::Greater => return cmp::Ordering::Greater,
338 }
339 }
340 cmp::Ordering::Equal
341 }
342 }
343 }
344}
345
346impl Hash for Key {
347 #[inline]
348 fn hash<H: Hasher>(&self, state: &mut H) {
349 state.write_u64(self.hash)
355 }
356}
357
358impl fmt::Display for Key {
359 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
360 if self.labels.is_empty() {
361 write!(f, "Key({})", self.name.as_str())
362 } else {
363 write!(f, "Key({}, [", self.name.as_str())?;
364 let mut first = true;
365 for label in self.labels.as_ref() {
366 if first {
367 write!(f, "{} = {}", label.0, label.1)?;
368 first = false;
369 } else {
370 write!(f, ", {} = {}", label.0, label.1)?;
371 }
372 }
373 write!(f, "])")
374 }
375 }
376}
377
378impl<T> From<T> for Key
379where
380 T: Into<KeyName>,
381{
382 fn from(name: T) -> Self {
383 Self::from_name(name)
384 }
385}
386
387impl<N, L> From<(N, L)> for Key
388where
389 N: Into<KeyName>,
390 L: IntoLabels,
391{
392 fn from(parts: (N, L)) -> Self {
393 Self::from_parts(parts.0, parts.1)
394 }
395}
396
397#[cfg(test)]
398mod tests {
399 use super::Key;
400 use crate::{KeyName, Label};
401 use std::{cmp, collections::HashMap, ops::Deref, sync::Arc};
402
403 static BORROWED_NAME: &str = "name";
404 static FOOBAR_NAME: &str = "foobar";
405 static BORROWED_BASIC: Key = Key::from_static_name(BORROWED_NAME);
406 static LABELS: [Label; 1] = [Label::from_static_parts("key", "value")];
407 static BORROWED_LABELS: Key = Key::from_static_parts(BORROWED_NAME, &LABELS);
408
409 #[test]
410 fn test_key_ord_and_partialord() {
411 let keys_expected: Vec<Key> =
412 vec![Key::from_name("aaaa"), Key::from_name("bbbb"), Key::from_name("cccc")];
413
414 let keys_unsorted: Vec<Key> =
415 vec![Key::from_name("bbbb"), Key::from_name("cccc"), Key::from_name("aaaa")];
416
417 let keys = {
418 let mut keys = keys_unsorted.clone();
419 keys.sort();
420 keys
421 };
422 assert_eq!(keys, keys_expected);
423
424 let keys = {
425 let mut keys = keys_unsorted.clone();
426 keys.sort_by(|a, b| a.partial_cmp(b).unwrap());
427 keys
428 };
429 assert_eq!(keys, keys_expected);
430 }
431
432 #[test]
433 fn test_key_ord_total() {
434 let mut keys: Vec<_> = (1..16)
435 .flat_map(|i| {
436 let names: Vec<Label> =
437 (0..i).map(|s| Label::new(format!("{}", s), format!("{}", s))).collect();
438 let key1 = Key::from_parts("key", names.clone());
439
440 let mut names_alt = names.clone();
442 names_alt.rotate_left(1);
443 let key2 = Key::from_parts("key", names_alt);
444 assert_eq!(key1, key2);
445
446 names_alt = names.clone();
448 names_alt[0] = Label::new("x".to_string(), "0".to_string());
449 let key3 = Key::from_parts("key", names_alt);
450 assert_ne!(key1, key3);
451
452 names_alt = names.clone();
454 names_alt[i - 1] = Label::new("x".to_string(), "0".to_string());
455 let key4 = Key::from_parts("key", names_alt);
456 assert_ne!(key1, key4);
457
458 [key1, key2, key3, key4]
459 })
460 .collect();
461 keys.push(Key::from_parts("key", vec![]));
462 keys.sort();
463 for i in 0..keys.len() {
464 for j in 0..keys.len() {
465 match (keys[i] == keys[j], keys[i].cmp(&keys[j])) {
467 (true, cmp::Ordering::Equal) => {}
468 (true, cmp::Ordering::Less) => panic!("at {} {} equal keys compared lt", i, j),
469 (true, cmp::Ordering::Greater) => {
470 panic!("at {} {} equal keys compared gt", i, j)
471 }
472 (false, cmp::Ordering::Equal) => {
473 panic!("at {} {} unequal keys compared equal", i, j)
474 }
475 (false, cmp::Ordering::Less) => assert!(i < j),
476 (false, cmp::Ordering::Greater) => assert!(i > j),
477 }
478 }
479 }
480 }
481
482 #[test]
483 fn test_key_eq_and_hash() {
484 let mut keys = HashMap::new();
485
486 let owned_basic: Key = Key::from_name("name");
487 assert_eq!(&owned_basic, &BORROWED_BASIC);
488
489 let previous = keys.insert(owned_basic, 42);
490 assert!(previous.is_none());
491
492 let previous = keys.get(&BORROWED_BASIC);
493 assert_eq!(previous, Some(&42));
494
495 let labels = LABELS.to_vec();
496 let owned_labels = Key::from_parts(BORROWED_NAME, labels);
497 assert_eq!(&owned_labels, &BORROWED_LABELS);
498
499 let previous = keys.insert(owned_labels, 43);
500 assert!(previous.is_none());
501
502 let previous = keys.get(&BORROWED_LABELS);
503 assert_eq!(previous, Some(&43));
504
505 let basic: Key = "constant_key".into();
506 let cloned_basic = basic.clone();
507 assert_eq!(basic, cloned_basic);
508
509 for i in 1..16 {
510 let names: Vec<Label> =
511 (0..i).map(|s| Label::new(format!("{}", s), format!("{}", s))).collect();
512 let key1 = Key::from_parts("key", names.clone());
513 let mut names_alt = names.clone();
514
515 names_alt.rotate_left(1);
517 let key2 = Key::from_parts("key", names_alt);
518 assert_eq!(key1, key2);
519 assert_eq!(key1.get_hash(), key2.get_hash());
520
521 names_alt = names.clone();
523 names_alt[0] = Label::new("x".to_string(), "0".to_string());
524 let key2 = Key::from_parts("key", names_alt);
525 assert_ne!(key1, key2);
526 assert_ne!(key1.get_hash(), key2.get_hash());
527
528 names_alt = names.clone();
530 names_alt[i - 1] = Label::new("x".to_string(), "0".to_string());
531 let key2 = Key::from_parts("key", names_alt);
532 assert_ne!(key1, key2);
533 assert_ne!(key1.get_hash(), key2.get_hash());
534
535 let key2 = Key::from_parts("key", vec![]);
537 assert_ne!(key1, key2);
538 assert_ne!(key1.get_hash(), key2.get_hash());
539 }
540 }
541
542 #[test]
543 fn test_key_data_proper_display() {
544 let key1 = Key::from_name("foobar");
545 let result1 = key1.to_string();
546 assert_eq!(result1, "Key(foobar)");
547
548 let key2 = Key::from_parts(FOOBAR_NAME, vec![Label::new("system", "http")]);
549 let result2 = key2.to_string();
550 assert_eq!(result2, "Key(foobar, [system = http])");
551
552 let key3 = Key::from_parts(
553 FOOBAR_NAME,
554 vec![Label::new("system", "http"), Label::new("user", "joe")],
555 );
556 let result3 = key3.to_string();
557 assert_eq!(result3, "Key(foobar, [system = http, user = joe])");
558
559 let key4 = Key::from_parts(
560 FOOBAR_NAME,
561 vec![
562 Label::new("black", "black"),
563 Label::new("lives", "lives"),
564 Label::new("matter", "matter"),
565 ],
566 );
567 let result4 = key4.to_string();
568 assert_eq!(result4, "Key(foobar, [black = black, lives = lives, matter = matter])");
569 }
570
571 #[test]
572 fn test_key_name_equality() {
573 static KEY_NAME: &str = "key_name";
574
575 let borrowed_const = KeyName::from_const_str(KEY_NAME);
576 let borrowed_nonconst = KeyName::from(KEY_NAME);
577 let owned = KeyName::from(KEY_NAME.to_owned());
578
579 let shared_arc = Arc::from(KEY_NAME);
580 let shared = KeyName::from(Arc::clone(&shared_arc));
581
582 assert_eq!(borrowed_const, borrowed_nonconst);
583 assert_eq!(borrowed_const.as_str(), borrowed_nonconst.as_str());
584 assert_eq!(borrowed_const, owned);
585 assert_eq!(borrowed_const.as_str(), owned.as_str());
586 assert_eq!(borrowed_const, shared);
587 assert_eq!(borrowed_const.as_str(), shared.as_str());
588 }
589
590 #[test]
591 fn test_shared_key_name_drop_logic() {
592 let shared_arc = Arc::from("foo");
593 let shared = KeyName::from(Arc::clone(&shared_arc));
594
595 assert_eq!(shared_arc.deref(), shared.as_str());
596
597 assert_eq!(Arc::strong_count(&shared_arc), 2);
598 drop(shared);
599 assert_eq!(Arc::strong_count(&shared_arc), 1);
600
601 let shared_weak = Arc::downgrade(&shared_arc);
602 assert_eq!(Arc::strong_count(&shared_arc), 1);
603
604 let shared = KeyName::from(Arc::clone(&shared_arc));
605 assert_eq!(shared_arc.deref(), shared.as_str());
606 assert_eq!(Arc::strong_count(&shared_arc), 2);
607
608 drop(shared_arc);
609 assert_eq!(shared_weak.strong_count(), 1);
610
611 drop(shared);
612 assert_eq!(shared_weak.strong_count(), 0);
613 }
614
615 #[test]
616 fn test_key_to_retained_preserves_equality_and_hash() {
617 let key = Key::from_parts(
618 String::from("retained"),
619 vec![Label::new(String::from("service"), String::from("api"))],
620 );
621
622 let retained = key.to_retained();
623
624 assert_eq!(key, retained);
625 assert_eq!(key.get_hash(), retained.get_hash());
626 assert_eq!(retained, retained.clone());
627 }
628
629 #[test]
630 fn test_buildhasherdefault_keyhasher_agrees_with_get_hash() {
631 use std::hash::{BuildHasher, BuildHasherDefault};
632 #[allow(deprecated)]
633 use crate::KeyHasher;
634
635 let key = Key::from_parts("regression", vec![Label::new("a", "1")]);
642 #[allow(deprecated)]
643 let via_buildhasher = BuildHasherDefault::<KeyHasher>::default().hash_one(&key);
644 assert_eq!(via_buildhasher, key.get_hash());
645 }
646
647 #[test]
648 fn test_keyhasher_byte_mode_distinguishes_inputs() {
649 use std::hash::{BuildHasher, BuildHasherDefault};
650 #[allow(deprecated)]
651 use crate::KeyHasher;
652
653 #[allow(deprecated)]
657 let bh = BuildHasherDefault::<KeyHasher>::default();
658 let h_foo_1 = bh.hash_one("foo");
659 let h_foo_2 = bh.hash_one("foo");
660 let h_bar = bh.hash_one("bar");
661 assert_eq!(h_foo_1, h_foo_2);
662 assert_ne!(h_foo_1, h_bar);
663 }
664}