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]);