use std::{ cmp::Ordering, convert::TryFrom, fmt, hash::{Hash, Hasher}, marker::PhantomData, rc::Rc, str::FromStr, sync::Arc, }; use crate::{crypto_algorithms::SigningKeyAlgorithm, DeviceId, KeyName}; /// A key algorithm and key name delimited by a colon. #[repr(transparent)] pub struct KeyId(PhantomData<(A, K)>, str); impl KeyId { /// Creates a new `KeyId` from an algorithm and key name. pub fn from_parts(algorithm: A, key_name: &K) -> Box where A: AsRef, K: AsRef, { let algorithm = algorithm.as_ref(); let key_name = key_name.as_ref(); let mut res = String::with_capacity(algorithm.len() + 1 + key_name.len()); res.push_str(algorithm); res.push(':'); res.push_str(key_name); Self::from_owned(res.into()) } /// Returns key algorithm of the key ID. pub fn algorithm(&self) -> A where A: FromStr, { A::from_str(&self.as_str()[..self.colon_idx()]).unwrap_or_else(|_| unreachable!()) } /// Returns the key name of the key ID. pub fn key_name<'a>(&'a self) -> &'a K where &'a K: From<&'a str>, { self.as_str()[self.colon_idx() + 1..].into() } /// Creates a string slice from this `KeyId`. pub fn as_str(&self) -> &str { &self.1 } /// Creates a byte slice from this `KeyId`. pub fn as_bytes(&self) -> &[u8] { self.1.as_bytes() } fn from_borrowed(s: &str) -> &Self { unsafe { std::mem::transmute(s) } } fn from_owned(s: Box) -> Box { unsafe { Box::from_raw(Box::into_raw(s) as _) } } fn into_owned(self: Box) -> Box { unsafe { Box::from_raw(Box::into_raw(self) as _) } } fn colon_idx(&self) -> usize { self.as_str().find(':').unwrap() } } /// Algorithm + key name for signing keys. pub type SigningKeyId = KeyId; /// Algorithm + key name for homeserver signing keys. pub type ServerSigningKeyId = SigningKeyId; /// Algorithm + key name for device keys. pub type DeviceSigningKeyId = SigningKeyId; impl Clone for Box> { fn clone(&self) -> Self { (**self).to_owned() } } impl ToOwned for KeyId { type Owned = Box>; fn to_owned(&self) -> Self::Owned { Self::from_owned(self.1.into()) } } impl From<&KeyId> for Box> { fn from(id: &KeyId) -> Self { id.to_owned() } } impl AsRef for Box> { fn as_ref(&self) -> &str { self.as_str() } } impl From<&KeyId> for Rc> { fn from(s: &KeyId) -> Rc> { let rc = Rc::::from(s.as_str()); unsafe { Rc::from_raw(Rc::into_raw(rc) as *const KeyId) } } } impl From<&KeyId> for Arc> { fn from(s: &KeyId) -> Arc> { let arc = Arc::::from(s.as_str()); unsafe { Arc::from_raw(Arc::into_raw(arc) as *const KeyId) } } } impl PartialEq> for Box> { fn eq(&self, other: &KeyId) -> bool { self.as_str() == other.as_str() } } impl PartialEq<&'_ KeyId> for Box> { fn eq(&self, other: &&KeyId) -> bool { self.as_str() == other.as_str() } } impl PartialEq>> for KeyId { fn eq(&self, other: &Box>) -> bool { self.as_str() == other.as_str() } } impl PartialEq>> for &'_ KeyId { fn eq(&self, other: &Box>) -> bool { self.as_str() == other.as_str() } } impl AsRef for KeyId { fn as_ref(&self) -> &str { self.as_str() } } impl fmt::Display for KeyId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.as_str().fmt(f) } } impl fmt::Debug for KeyId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.as_str().fmt(f) } } impl PartialEq for KeyId { fn eq(&self, other: &Self) -> bool { self.as_str() == other.as_str() } } impl Eq for KeyId {} impl PartialOrd for KeyId { fn partial_cmp(&self, other: &Self) -> Option { PartialOrd::partial_cmp(self.as_str(), other.as_str()) } } impl Ord for KeyId { fn cmp(&self, other: &Self) -> Ordering { Ord::cmp(self.as_str(), other.as_str()) } } impl Hash for KeyId { fn hash(&self, state: &mut H) { self.as_str().hash(state); } } #[cfg(feature = "serde")] impl serde::Serialize for KeyId { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { serializer.serialize_str(self.as_str()) } } impl From>> for String { fn from(id: Box>) -> Self { id.into_owned().into() } } #[cfg(feature = "serde")] impl<'de, A, K: ?Sized> serde::Deserialize<'de> for Box> { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { use serde::de::Error; let s = String::deserialize(deserializer)?; match try_from(s) { Ok(o) => Ok(o), Err(e) => Err(D::Error::custom(e)), } } } fn try_from(s: S) -> Result>, crate::Error> where S: AsRef + Into>, { ruma_identifiers_validation::key_id::validate(s.as_ref())?; Ok(KeyId::from_owned(s.into())) } impl<'a, A, K: ?Sized> TryFrom<&'a str> for &'a KeyId { type Error = crate::Error; fn try_from(s: &'a str) -> Result { (ruma_identifiers_validation::key_id::validate)(s)?; Ok(KeyId::from_borrowed(s)) } } impl FromStr for Box> { type Err = crate::Error; fn from_str(s: &str) -> Result { try_from(s) } } impl TryFrom<&str> for Box> { type Error = crate::Error; fn try_from(s: &str) -> Result { try_from(s) } } impl TryFrom for Box> { type Error = crate::Error; fn try_from(s: String) -> Result { try_from(s) } } #[rustfmt::skip] partial_eq_string!(KeyId [A, K]);