use std::{
cmp::Ordering,
hash::{Hash, Hasher},
marker::PhantomData,
str::FromStr,
};
use ruma_macros::IdZst;
use super::{crypto_algorithms::SigningKeyAlgorithm, DeviceId, KeyName};
/// A key algorithm and key name delimited by a colon.
#[repr(transparent)]
#[derive(IdZst)]
#[ruma_id(validate = ruma_identifiers_validation::key_id::validate)]
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) -> OwnedKeyId
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_borrowed(&res).to_owned()
}
/// 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()
}
fn colon_idx(&self) -> usize {
self.as_str().find(':').unwrap()
}
}
/// Algorithm + key name for signing keys.
pub type SigningKeyId = KeyId;
/// Algorithm + key name for signing keys.
pub type OwnedSigningKeyId = OwnedKeyId;
/// Algorithm + key name for homeserver signing keys.
pub type ServerSigningKeyId = SigningKeyId;
/// Algorithm + key name for homeserver signing keys.
pub type OwnedServerSigningKeyId = OwnedSigningKeyId;
/// Algorithm + key name for device keys.
pub type DeviceSigningKeyId = SigningKeyId;
/// Algorithm + key name for device keys.
pub type OwnedDeviceSigningKeyId = OwnedSigningKeyId;
// The following impls are usually derived using the std macros.
// They are implemented manually here to avoid unnecessary bounds.
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 {
Some(self.cmp(other))
}
}
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);
}
}