use std::fmt;
use quickcheck::{Arbitrary, Gen};
use crate::Error;
use crate::Fingerprint;
use crate::KeyID;
use crate::Result;
impl fmt::Display for KeyID {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.convert_to_string(true))
}
}
impl fmt::Debug for KeyID {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("KeyID")
.field(&self.to_string())
.finish()
}
}
impl std::str::FromStr for KeyID {
type Err = failure::Error;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
Self::from_hex(s)
}
}
impl From<KeyID> for Vec<u8> {
fn from(id: KeyID) -> Self {
let mut r = Vec::with_capacity(8);
match id {
KeyID::V4(ref b) => r.extend_from_slice(b),
KeyID::Invalid(ref b) => r.extend_from_slice(b),
}
r
}
}
impl From<u64> for KeyID {
fn from(id: u64) -> Self {
Self::new(id)
}
}
impl From<&Fingerprint> for KeyID {
fn from(fp: &Fingerprint) -> Self {
match fp {
Fingerprint::V4(fp) =>
KeyID::from_bytes(&fp[fp.len() - 8..]),
Fingerprint::Invalid(fp) => {
KeyID::Invalid(fp.clone())
}
}
}
}
impl From<Fingerprint> for KeyID {
fn from(fp: Fingerprint) -> Self {
match fp {
Fingerprint::V4(fp) =>
KeyID::from_bytes(&fp[fp.len() - 8..]),
Fingerprint::Invalid(fp) => {
KeyID::Invalid(fp)
}
}
}
}
impl KeyID {
pub fn new(data: u64) -> KeyID {
let bytes = [
(data >> (7 * 8)) as u8,
(data >> (6 * 8)) as u8,
(data >> (5 * 8)) as u8,
(data >> (4 * 8)) as u8,
(data >> (3 * 8)) as u8,
(data >> (2 * 8)) as u8,
(data >> (1 * 8)) as u8,
(data >> (0 * 8)) as u8
];
Self::from_bytes(&bytes[..])
}
pub fn as_u64(&self) -> Result<u64> {
match &self {
KeyID::V4(ref b) =>
Ok(0u64
| ((b[0] as u64) << (7 * 8))
| ((b[1] as u64) << (6 * 8))
| ((b[2] as u64) << (5 * 8))
| ((b[3] as u64) << (4 * 8))
| ((b[4] as u64) << (3 * 8))
| ((b[5] as u64) << (2 * 8))
| ((b[6] as u64) << (1 * 8))
| ((b[7] as u64) << (0 * 8))),
KeyID::Invalid(_) =>
Err(Error::InvalidArgument("Invalid KeyID".into()).into()),
}
}
pub fn from_bytes(raw: &[u8]) -> KeyID {
if raw.len() == 8 {
let mut keyid : [u8; 8] = Default::default();
keyid.copy_from_slice(raw);
KeyID::V4(keyid)
} else {
KeyID::Invalid(raw.to_vec().into_boxed_slice())
}
}
pub fn from_hex(hex: &str) -> Result<KeyID> {
let bytes = crate::fmt::from_hex(hex, true)?;
if bytes.len() == 8 {
Ok(KeyID::from_bytes(&bytes[..]))
} else {
Ok(Fingerprint::from_hex(hex)?.into())
}
}
pub fn as_slice(&self) -> &[u8] {
match self {
&KeyID::V4(ref id) => id,
&KeyID::Invalid(ref id) => id,
}
}
pub fn wildcard() -> Self {
Self::from_bytes(&[0u8; 8][..])
}
pub fn is_wildcard(&self) -> bool {
self.as_slice().iter().all(|b| *b == 0)
}
pub fn to_hex(&self) -> String {
self.convert_to_string(false)
}
fn convert_to_string(&self, pretty: bool) -> String {
let raw = match self {
&KeyID::V4(ref fp) => &fp[..],
&KeyID::Invalid(ref fp) => &fp[..],
};
let mut output = Vec::with_capacity(
raw.len() * 2
+ if pretty {
raw.len() / 2
} else { 0 });
for (i, b) in raw.iter().enumerate() {
if pretty && i > 0 && i % 2 == 0 {
output.push(' ' as u8);
}
let top = b >> 4;
let bottom = b & 0xFu8;
if top < 10u8 {
output.push('0' as u8 + top)
} else {
output.push('A' as u8 + (top - 10u8))
}
if bottom < 10u8 {
output.push('0' as u8 + bottom)
} else {
output.push('A' as u8 + (bottom - 10u8))
}
}
String::from_utf8(output).unwrap()
}
}
impl Arbitrary for KeyID {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
KeyID::new(u64::arbitrary(g))
}
}
#[cfg(test)]
mod test {
use super::*;
quickcheck! {
fn u64_roundtrip(id: u64) -> bool {
KeyID::new(id).as_u64().unwrap() == id
}
}
#[test]
fn from_hex() {
KeyID::from_hex("FB3751F1587DAEF1").unwrap();
KeyID::from_hex("39D100AB67D5BD8C04010205FB3751F1587DAEF1")
.unwrap();
KeyID::from_hex("0xFB3751F1587DAEF1").unwrap();
KeyID::from_hex("0x39D100AB67D5BD8C04010205FB3751F1587DAEF1")
.unwrap();
KeyID::from_hex("FB37 51F1 587D AEF1").unwrap();
KeyID::from_hex("39D1 00AB 67D5 BD8C 0401 0205 FB37 51F1 587D AEF1")
.unwrap();
KeyID::from_hex("GB3751F1587DAEF1").unwrap_err();
KeyID::from_hex("EFB3751F1587DAEF1").unwrap_err();
KeyID::from_hex("%FB3751F1587DAEF1").unwrap_err();
assert_match!(KeyID::Invalid(_) = KeyID::from_hex("587DAEF1").unwrap());
assert_match!(KeyID::Invalid(_) =
KeyID::from_hex("0x587DAEF1").unwrap());
}
#[test]
fn keyid_is_send_and_sync() {
fn f<T: Send + Sync>(_: T) {}
f(KeyID::from_hex("89AB CDEF 0123 4567").unwrap());
}
}