use std::{borrow::Borrow, fmt}; use crate::{ error::{Error, NonEmptyStringError}, utils, }; /// An owned structured field value [key]. /// /// Keys must match the following regular expression: /// /// ```re /// ^[A-Za-z*][A-Za-z*0-9!#$%&'+\-.^_`|~]*$ /// ``` /// /// [key]: #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Key(String); /// A borrowed structured field value [key]. /// /// Keys must match the following regular expression: /// /// ```re /// ^[A-Za-z*][A-Za-z*0-9!#$%&'+\-.^_`|~]*$ /// ``` /// /// This type is to [`Key`] as [`str`] is to [`String`]. /// /// [key]: #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, ref_cast::RefCastCustom)] #[repr(transparent)] pub struct KeyRef(str); const fn validate(v: &[u8]) -> Result<(), NonEmptyStringError> { if v.is_empty() { return Err(NonEmptyStringError::empty()); } if !utils::is_allowed_start_key_char(v[0]) { return Err(NonEmptyStringError::invalid_character(0)); } let mut index = 1; while index < v.len() { if !utils::is_allowed_inner_key_char(v[index]) { return Err(NonEmptyStringError::invalid_character(index)); } index += 1; } Ok(()) } impl KeyRef { #[ref_cast::ref_cast_custom] const fn cast(v: &str) -> &Self; /// Creates a `&KeyRef` from a `&str`. /// /// # Errors /// If the input string validation fails. #[allow(clippy::should_implement_trait)] pub fn from_str(v: &str) -> Result<&Self, Error> { validate(v.as_bytes())?; Ok(Self::cast(v)) } // Like `from_str`, but assumes that the contents of the string have already // been validated as a key. pub(crate) fn from_validated_str(v: &str) -> &Self { debug_assert!(validate(v.as_bytes()).is_ok()); Self::cast(v) } /// Creates a `&KeyRef`, panicking if the value is invalid. /// /// This method is intended to be called from `const` contexts in which the /// value is known to be valid. Use [`KeyRef::from_str`] for non-panicking /// conversions. /// /// # Errors /// If the input string validation fails. #[must_use] pub const fn constant(v: &str) -> &Self { match validate(v.as_bytes()) { Ok(()) => Self::cast(v), Err(err) => panic!("{}", err.msg()), } } /// Returns the key as a `&str`. #[must_use] pub fn as_str(&self) -> &str { &self.0 } } impl ToOwned for KeyRef { type Owned = Key; fn to_owned(&self) -> Key { Key(self.0.to_owned()) } fn clone_into(&self, target: &mut Key) { self.0.clone_into(&mut target.0); } } impl Borrow for Key { fn borrow(&self) -> &KeyRef { self } } impl std::ops::Deref for Key { type Target = KeyRef; fn deref(&self) -> &KeyRef { KeyRef::cast(&self.0) } } impl From for String { fn from(v: Key) -> String { v.0 } } impl TryFrom for Key { type Error = Error; fn try_from(v: String) -> Result { validate(v.as_bytes())?; Ok(Key(v)) } } impl Key { /// Creates a `Key` from a `String`. /// /// Returns the original value if the conversion failed. /// /// # Errors /// If the input string validation fails. pub fn from_string(v: String) -> Result { match validate(v.as_bytes()) { Ok(()) => Ok(Self(v)), Err(err) => Err((err.into(), v)), } } } /// Creates a `&KeyRef`, panicking if the value is invalid. /// /// This is a convenience free function for [`KeyRef::constant`]. /// /// This method is intended to be called from `const` contexts in which the /// value is known to be valid. Use [`KeyRef::from_str`] for non-panicking /// conversions. #[must_use] pub const fn key_ref(v: &str) -> &KeyRef { KeyRef::constant(v) } impl fmt::Display for KeyRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.as_str()) } } impl fmt::Display for Key { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ::fmt(self, f) } } macro_rules! impl_eq { ($a: ty, $b: ty) => { impl PartialEq<$a> for $b { fn eq(&self, other: &$a) -> bool { ::eq(self, other) } } impl PartialEq<$b> for $a { fn eq(&self, other: &$b) -> bool { ::eq(self, other) } } }; } impl_eq!(Key, KeyRef); impl_eq!(Key, &KeyRef); impl<'a> TryFrom<&'a str> for &'a KeyRef { type Error = Error; fn try_from(v: &'a str) -> Result<&'a KeyRef, Error> { KeyRef::from_str(v) } } impl Borrow for Key { fn borrow(&self) -> &str { self.as_str() } } impl Borrow for KeyRef { fn borrow(&self) -> &str { self.as_str() } } impl AsRef for Key { fn as_ref(&self) -> &KeyRef { self } } impl AsRef for KeyRef { fn as_ref(&self) -> &KeyRef { self } } #[cfg(feature = "arbitrary")] impl<'a> arbitrary::Arbitrary<'a> for &'a KeyRef { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { KeyRef::from_str(<&str>::arbitrary(u)?).map_err(|_| arbitrary::Error::IncorrectFormat) } fn size_hint(_depth: usize) -> (usize, Option) { (1, None) } } #[cfg(feature = "arbitrary")] impl<'a> arbitrary::Arbitrary<'a> for Key { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { <&KeyRef>::arbitrary(u).map(ToOwned::to_owned) } fn size_hint(_depth: usize) -> (usize, Option) { (1, None) } }