1#![allow(clippy::upper_case_acronyms)]
2
3use super::encoding::{
4 Ascii, Binary, InvalidMetadataValue, InvalidMetadataValueBytes, ValueEncoding,
5};
6use super::key::MetadataKey;
7
8use bytes::Bytes;
9use http::header::HeaderValue;
10use std::error::Error;
11use std::hash::{Hash, Hasher};
12use std::marker::PhantomData;
13use std::str::FromStr;
14use std::{cmp, fmt};
15
16#[derive(Clone)]
23#[repr(transparent)]
24pub struct MetadataValue<VE: ValueEncoding> {
25 pub(crate) inner: HeaderValue,
28 phantom: PhantomData<VE>,
29}
30
31#[derive(Debug)]
36pub struct ToStrError {
37 _priv: (),
38}
39
40pub type AsciiMetadataValue = MetadataValue<Ascii>;
42pub type BinaryMetadataValue = MetadataValue<Binary>;
44
45impl<VE: ValueEncoding> MetadataValue<VE> {
46 #[inline]
73 pub fn from_static(src: &'static str) -> Self {
74 MetadataValue {
75 inner: VE::from_static(src),
76 phantom: PhantomData,
77 }
78 }
79
80 #[inline]
108 pub fn try_from_bytes(src: &[u8]) -> Result<Self, InvalidMetadataValueBytes> {
109 VE::from_bytes(src).map(|value| MetadataValue {
110 inner: value,
111 phantom: PhantomData,
112 })
113 }
114
115 #[inline]
129 pub fn from_shared(src: Bytes) -> Result<Self, InvalidMetadataValueBytes> {
130 VE::from_shared(src).map(|value| MetadataValue {
131 inner: value,
132 phantom: PhantomData,
133 })
134 }
135
136 #[inline]
145 pub unsafe fn from_shared_unchecked(src: Bytes) -> Self {
146 MetadataValue {
147 inner: HeaderValue::from_maybe_shared_unchecked(src),
148 phantom: PhantomData,
149 }
150 }
151
152 #[inline]
165 pub fn is_empty(&self) -> bool {
166 VE::is_empty(self.inner.as_bytes())
167 }
168
169 #[inline]
187 pub fn to_bytes(&self) -> Result<Bytes, InvalidMetadataValueBytes> {
188 VE::decode(self.inner.as_bytes())
189 }
190
191 #[inline]
206 pub fn set_sensitive(&mut self, val: bool) {
207 self.inner.set_sensitive(val);
208 }
209
210 #[inline]
232 pub fn is_sensitive(&self) -> bool {
233 self.inner.is_sensitive()
234 }
235
236 #[inline]
253 pub fn as_encoded_bytes(&self) -> &[u8] {
254 self.inner.as_bytes()
255 }
256
257 #[inline]
261 pub(crate) fn unchecked_from_header_value(value: HeaderValue) -> Self {
262 MetadataValue {
263 inner: value,
264 phantom: PhantomData,
265 }
266 }
267
268 #[inline]
272 pub(crate) fn unchecked_from_header_value_ref(header_value: &HeaderValue) -> &Self {
273 unsafe { &*(header_value as *const HeaderValue as *const Self) }
274 }
275
276 #[inline]
280 pub(crate) fn unchecked_from_mut_header_value_ref(header_value: &mut HeaderValue) -> &mut Self {
281 unsafe { &mut *(header_value as *mut HeaderValue as *mut Self) }
282 }
283}
284
285#[allow(clippy::len_without_is_empty)]
287impl MetadataValue<Ascii> {
288 #[allow(clippy::should_implement_trait)]
314 #[inline]
315 pub fn from_str(src: &str) -> Result<Self, InvalidMetadataValue> {
316 HeaderValue::from_str(src)
317 .map(|value| MetadataValue {
318 inner: value,
319 phantom: PhantomData,
320 })
321 .map_err(|_| InvalidMetadataValue::new())
322 }
323
324 #[inline]
337 pub fn from_key<KeyVE: ValueEncoding>(key: MetadataKey<KeyVE>) -> Self {
338 key.into()
339 }
340
341 #[inline]
356 pub fn len(&self) -> usize {
357 self.inner.len()
358 }
359
360 pub fn to_str(&self) -> Result<&str, ToStrError> {
374 self.inner.to_str().map_err(|_| ToStrError::new())
375 }
376
377 #[inline]
388 pub fn as_bytes(&self) -> &[u8] {
389 self.inner.as_bytes()
390 }
391}
392
393impl MetadataValue<Binary> {
394 #[inline]
404 pub fn from_bytes(src: &[u8]) -> Self {
405 Self::try_from_bytes(src).unwrap()
407 }
408}
409
410impl<VE: ValueEncoding> AsRef<[u8]> for MetadataValue<VE> {
411 #[inline]
412 fn as_ref(&self) -> &[u8] {
413 self.inner.as_ref()
414 }
415}
416
417impl<VE: ValueEncoding> fmt::Debug for MetadataValue<VE> {
418 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
419 VE::fmt(&self.inner, f)
420 }
421}
422
423impl<KeyVE: ValueEncoding> From<MetadataKey<KeyVE>> for MetadataValue<Ascii> {
424 #[inline]
425 fn from(h: MetadataKey<KeyVE>) -> MetadataValue<Ascii> {
426 MetadataValue {
427 inner: h.inner.into(),
428 phantom: PhantomData,
429 }
430 }
431}
432
433macro_rules! from_integers {
434 ($($name:ident: $t:ident => $max_len:expr),*) => {$(
435 impl From<$t> for MetadataValue<Ascii> {
436 fn from(num: $t) -> MetadataValue<Ascii> {
437 MetadataValue {
438 inner: HeaderValue::from(num),
439 phantom: PhantomData,
440 }
441 }
442 }
443
444 #[test]
445 fn $name() {
446 let n: $t = 55;
447 let val = AsciiMetadataValue::from(n);
448 assert_eq!(val, &n.to_string());
449
450 let n = ::std::$t::MAX;
451 let val = AsciiMetadataValue::from(n);
452 assert_eq!(val, &n.to_string());
453 }
454 )*};
455}
456
457from_integers! {
458 from_u16: u16 => 5,
462 from_i16: i16 => 6,
463 from_u32: u32 => 10,
464 from_i32: i32 => 11,
465 from_u64: u64 => 20,
466 from_i64: i64 => 20
467}
468
469#[cfg(target_pointer_width = "16")]
470from_integers! {
471 from_usize: usize => 5,
472 from_isize: isize => 6
473}
474
475#[cfg(target_pointer_width = "32")]
476from_integers! {
477 from_usize: usize => 10,
478 from_isize: isize => 11
479}
480
481#[cfg(target_pointer_width = "64")]
482from_integers! {
483 from_usize: usize => 20,
484 from_isize: isize => 20
485}
486
487#[cfg(test)]
488mod from_metadata_value_tests {
489 use super::*;
490 use crate::metadata::map::MetadataMap;
491
492 #[test]
493 fn it_can_insert_metadata_key_as_metadata_value() {
494 let mut map = MetadataMap::new();
495 map.insert(
496 "accept",
497 MetadataKey::<Ascii>::from_bytes(b"hello-world")
498 .unwrap()
499 .into(),
500 );
501
502 assert_eq!(
503 map.get("accept").unwrap(),
504 AsciiMetadataValue::try_from_bytes(b"hello-world").unwrap()
505 );
506 }
507}
508
509impl FromStr for MetadataValue<Ascii> {
510 type Err = InvalidMetadataValue;
511
512 #[inline]
513 fn from_str(s: &str) -> Result<MetadataValue<Ascii>, Self::Err> {
514 MetadataValue::<Ascii>::from_str(s)
515 }
516}
517
518impl<VE: ValueEncoding> From<MetadataValue<VE>> for Bytes {
519 #[inline]
520 fn from(value: MetadataValue<VE>) -> Bytes {
521 Bytes::copy_from_slice(value.inner.as_bytes())
522 }
523}
524
525impl<'a, VE: ValueEncoding> From<&'a MetadataValue<VE>> for MetadataValue<VE> {
526 #[inline]
527 fn from(t: &'a MetadataValue<VE>) -> Self {
528 t.clone()
529 }
530}
531
532impl ToStrError {
535 pub(crate) fn new() -> Self {
536 ToStrError { _priv: () }
537 }
538}
539
540impl fmt::Display for ToStrError {
541 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
542 f.write_str("failed to convert metadata to a str")
543 }
544}
545
546impl Error for ToStrError {}
547
548impl Hash for MetadataValue<Ascii> {
549 fn hash<H: Hasher>(&self, state: &mut H) {
550 self.inner.hash(state)
551 }
552}
553
554impl Hash for MetadataValue<Binary> {
555 fn hash<H: Hasher>(&self, state: &mut H) {
556 match self.to_bytes() {
557 Ok(b) => b.hash(state),
558 Err(e) => e.hash(state),
559 }
560 }
561}
562
563impl<VE: ValueEncoding> PartialEq for MetadataValue<VE> {
566 #[inline]
567 fn eq(&self, other: &MetadataValue<VE>) -> bool {
568 VE::values_equal(&self.inner, &other.inner)
573 }
574}
575
576impl<VE: ValueEncoding> Eq for MetadataValue<VE> {}
577
578impl<VE: ValueEncoding> PartialOrd for MetadataValue<VE> {
579 #[inline]
580 fn partial_cmp(&self, other: &MetadataValue<VE>) -> Option<cmp::Ordering> {
581 self.inner.partial_cmp(&other.inner)
582 }
583}
584
585impl<VE: ValueEncoding> Ord for MetadataValue<VE> {
586 #[inline]
587 fn cmp(&self, other: &Self) -> cmp::Ordering {
588 self.inner.cmp(&other.inner)
589 }
590}
591
592impl<VE: ValueEncoding> PartialEq<str> for MetadataValue<VE> {
593 #[inline]
594 fn eq(&self, other: &str) -> bool {
595 VE::equals(&self.inner, other.as_bytes())
596 }
597}
598
599impl<VE: ValueEncoding> PartialEq<[u8]> for MetadataValue<VE> {
600 #[inline]
601 fn eq(&self, other: &[u8]) -> bool {
602 VE::equals(&self.inner, other)
603 }
604}
605
606impl<VE: ValueEncoding> PartialOrd<str> for MetadataValue<VE> {
607 #[inline]
608 fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
609 self.inner.partial_cmp(other.as_bytes())
610 }
611}
612
613impl<VE: ValueEncoding> PartialOrd<[u8]> for MetadataValue<VE> {
614 #[inline]
615 fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {
616 self.inner.partial_cmp(other)
617 }
618}
619
620impl<VE: ValueEncoding> PartialEq<MetadataValue<VE>> for str {
621 #[inline]
622 fn eq(&self, other: &MetadataValue<VE>) -> bool {
623 *other == *self
624 }
625}
626
627impl<VE: ValueEncoding> PartialEq<MetadataValue<VE>> for [u8] {
628 #[inline]
629 fn eq(&self, other: &MetadataValue<VE>) -> bool {
630 *other == *self
631 }
632}
633
634impl<VE: ValueEncoding> PartialOrd<MetadataValue<VE>> for str {
635 #[inline]
636 fn partial_cmp(&self, other: &MetadataValue<VE>) -> Option<cmp::Ordering> {
637 self.as_bytes().partial_cmp(other.inner.as_bytes())
638 }
639}
640
641impl<VE: ValueEncoding> PartialOrd<MetadataValue<VE>> for [u8] {
642 #[inline]
643 fn partial_cmp(&self, other: &MetadataValue<VE>) -> Option<cmp::Ordering> {
644 self.partial_cmp(other.inner.as_bytes())
645 }
646}
647
648impl<VE: ValueEncoding> PartialEq<String> for MetadataValue<VE> {
649 #[inline]
650 fn eq(&self, other: &String) -> bool {
651 *self == other[..]
652 }
653}
654
655impl<VE: ValueEncoding> PartialOrd<String> for MetadataValue<VE> {
656 #[inline]
657 fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
658 self.inner.partial_cmp(other.as_bytes())
659 }
660}
661
662impl<VE: ValueEncoding> PartialEq<MetadataValue<VE>> for String {
663 #[inline]
664 fn eq(&self, other: &MetadataValue<VE>) -> bool {
665 *other == *self
666 }
667}
668
669impl<VE: ValueEncoding> PartialOrd<MetadataValue<VE>> for String {
670 #[inline]
671 fn partial_cmp(&self, other: &MetadataValue<VE>) -> Option<cmp::Ordering> {
672 self.as_bytes().partial_cmp(other.inner.as_bytes())
673 }
674}
675
676impl<'a, VE: ValueEncoding> PartialEq<MetadataValue<VE>> for &'a MetadataValue<VE> {
677 #[inline]
678 fn eq(&self, other: &MetadataValue<VE>) -> bool {
679 **self == *other
680 }
681}
682
683impl<'a, VE: ValueEncoding> PartialOrd<MetadataValue<VE>> for &'a MetadataValue<VE> {
684 #[inline]
685 fn partial_cmp(&self, other: &MetadataValue<VE>) -> Option<cmp::Ordering> {
686 (**self).partial_cmp(other)
687 }
688}
689
690impl<'a, VE: ValueEncoding, T: ?Sized> PartialEq<&'a T> for MetadataValue<VE>
691where
692 MetadataValue<VE>: PartialEq<T>,
693{
694 #[inline]
695 fn eq(&self, other: &&'a T) -> bool {
696 *self == **other
697 }
698}
699
700impl<'a, VE: ValueEncoding, T: ?Sized> PartialOrd<&'a T> for MetadataValue<VE>
701where
702 MetadataValue<VE>: PartialOrd<T>,
703{
704 #[inline]
705 fn partial_cmp(&self, other: &&'a T) -> Option<cmp::Ordering> {
706 self.partial_cmp(*other)
707 }
708}
709
710impl<'a, VE: ValueEncoding> PartialEq<MetadataValue<VE>> for &'a str {
711 #[inline]
712 fn eq(&self, other: &MetadataValue<VE>) -> bool {
713 *other == *self
714 }
715}
716
717impl<'a, VE: ValueEncoding> PartialOrd<MetadataValue<VE>> for &'a str {
718 #[inline]
719 fn partial_cmp(&self, other: &MetadataValue<VE>) -> Option<cmp::Ordering> {
720 self.as_bytes().partial_cmp(other.inner.as_bytes())
721 }
722}
723
724#[test]
725fn test_debug() {
726 let cases = &[
727 ("hello", "\"hello\""),
728 ("hello \"world\"", "\"hello \\\"world\\\"\""),
729 ("\u{7FFF}hello", "\"\\xe7\\xbf\\xbfhello\""),
730 ];
731
732 for &(value, expected) in cases {
733 let val = AsciiMetadataValue::try_from_bytes(value.as_bytes()).unwrap();
734 let actual = format!("{:?}", val);
735 assert_eq!(expected, actual);
736 }
737
738 let mut sensitive = AsciiMetadataValue::from_static("password");
739 sensitive.set_sensitive(true);
740 assert_eq!("Sensitive", format!("{:?}", sensitive));
741}
742
743#[test]
744fn test_is_empty() {
745 fn from_str<VE: ValueEncoding>(s: &str) -> MetadataValue<VE> {
746 MetadataValue::<VE>::unchecked_from_header_value(s.parse().unwrap())
747 }
748
749 assert!(from_str::<Ascii>("").is_empty());
750 assert!(from_str::<Binary>("").is_empty());
751 assert!(!from_str::<Ascii>("a").is_empty());
752 assert!(!from_str::<Binary>("a").is_empty());
753 assert!(!from_str::<Ascii>("=").is_empty());
754 assert!(from_str::<Binary>("=").is_empty());
755 assert!(!from_str::<Ascii>("===").is_empty());
756 assert!(from_str::<Binary>("===").is_empty());
757 assert!(!from_str::<Ascii>("=====").is_empty());
758 assert!(from_str::<Binary>("=====").is_empty());
759}
760
761#[test]
762fn test_from_shared_base64_encodes() {
763 let value = BinaryMetadataValue::from_shared(Bytes::from_static(b"Hello")).unwrap();
764 assert_eq!(value.as_encoded_bytes(), b"SGVsbG8");
765}
766
767#[test]
768fn test_value_eq_value() {
769 type BMV = BinaryMetadataValue;
770 type AMV = AsciiMetadataValue;
771
772 assert_eq!(AMV::from_static("abc"), AMV::from_static("abc"));
773 assert_ne!(AMV::from_static("abc"), AMV::from_static("ABC"));
774
775 assert_eq!(BMV::from_bytes(b"abc"), BMV::from_bytes(b"abc"));
776 assert_ne!(BMV::from_bytes(b"abc"), BMV::from_bytes(b"ABC"));
777
778 assert_eq!(
780 BMV::from_static("SGVsbG8hIQ=="),
781 BMV::from_static("SGVsbG8hIQ")
782 );
783 unsafe {
785 assert_eq!(
786 BMV::from_shared_unchecked(Bytes::from_static(b"..{}")),
787 BMV::from_shared_unchecked(Bytes::from_static(b"{}.."))
788 );
789 }
790}
791
792#[test]
793fn test_value_eq_str() {
794 type BMV = BinaryMetadataValue;
795 type AMV = AsciiMetadataValue;
796
797 assert_eq!(AMV::from_static("abc"), "abc");
798 assert_ne!(AMV::from_static("abc"), "ABC");
799 assert_eq!("abc", AMV::from_static("abc"));
800 assert_ne!("ABC", AMV::from_static("abc"));
801
802 assert_eq!(BMV::from_bytes(b"abc"), "abc");
803 assert_ne!(BMV::from_bytes(b"abc"), "ABC");
804 assert_eq!("abc", BMV::from_bytes(b"abc"));
805 assert_ne!("ABC", BMV::from_bytes(b"abc"));
806
807 assert_eq!(BMV::from_static("SGVsbG8hIQ=="), "Hello!!");
809 assert_eq!("Hello!!", BMV::from_static("SGVsbG8hIQ=="));
810}
811
812#[test]
813fn test_value_eq_bytes() {
814 type BMV = BinaryMetadataValue;
815 type AMV = AsciiMetadataValue;
816
817 assert_eq!(AMV::from_static("abc"), "abc".as_bytes());
818 assert_ne!(AMV::from_static("abc"), "ABC".as_bytes());
819 assert_eq!(*"abc".as_bytes(), AMV::from_static("abc"));
820 assert_ne!(*"ABC".as_bytes(), AMV::from_static("abc"));
821
822 assert_eq!(*"abc".as_bytes(), BMV::from_bytes(b"abc"));
823 assert_ne!(*"ABC".as_bytes(), BMV::from_bytes(b"abc"));
824
825 assert_eq!(BMV::from_static("SGVsbG8hIQ=="), "Hello!!".as_bytes());
827 assert_eq!(*"Hello!!".as_bytes(), BMV::from_static("SGVsbG8hIQ=="));
828}
829
830#[test]
831fn test_ascii_value_hash() {
832 use std::collections::hash_map::DefaultHasher;
833 type AMV = AsciiMetadataValue;
834
835 fn hash(value: AMV) -> u64 {
836 let mut hasher = DefaultHasher::new();
837 value.hash(&mut hasher);
838 hasher.finish()
839 }
840
841 let value1 = AMV::from_static("abc");
842 let value2 = AMV::from_static("abc");
843 assert_eq!(value1, value2);
844 assert_eq!(hash(value1), hash(value2));
845
846 let value1 = AMV::from_static("abc");
847 let value2 = AMV::from_static("xyz");
848
849 assert_ne!(value1, value2);
850 assert_ne!(hash(value1), hash(value2));
851}
852
853#[test]
854fn test_valid_binary_value_hash() {
855 use std::collections::hash_map::DefaultHasher;
856 type BMV = BinaryMetadataValue;
857
858 fn hash(value: BMV) -> u64 {
859 let mut hasher = DefaultHasher::new();
860 value.hash(&mut hasher);
861 hasher.finish()
862 }
863
864 let value1 = BMV::from_bytes(b"abc");
865 let value2 = BMV::from_bytes(b"abc");
866 assert_eq!(value1, value2);
867 assert_eq!(hash(value1), hash(value2));
868
869 let value1 = BMV::from_bytes(b"abc");
870 let value2 = BMV::from_bytes(b"xyz");
871 assert_ne!(value1, value2);
872 assert_ne!(hash(value1), hash(value2));
873}
874
875#[test]
876fn test_invalid_binary_value_hash() {
877 use std::collections::hash_map::DefaultHasher;
878 type BMV = BinaryMetadataValue;
879
880 fn hash(value: BMV) -> u64 {
881 let mut hasher = DefaultHasher::new();
882 value.hash(&mut hasher);
883 hasher.finish()
884 }
885
886 unsafe {
887 let value1 = BMV::from_shared_unchecked(Bytes::from_static(b"..{}"));
888 let value2 = BMV::from_shared_unchecked(Bytes::from_static(b"{}.."));
889 assert_eq!(value1, value2);
890 assert_eq!(hash(value1), hash(value2));
891 }
892
893 unsafe {
894 let valid = BMV::from_bytes(b"abc");
895 let invalid = BMV::from_shared_unchecked(Bytes::from_static(b"{}.."));
896 assert_ne!(valid, invalid);
897 assert_ne!(hash(valid), hash(invalid));
898 }
899}