use std::fmt::Display;
use std::hash::Hash as StdHash;
use std::str::FromStr;
use ed25519_dalek::{PublicKey, PUBLIC_KEY_LENGTH};
use serde::{Deserialize, Deserializer, Serialize};
use crate::identity::error::AuthorError;
use crate::{Human, Validate};
#[derive(Clone, Debug, Serialize, Eq, StdHash, PartialEq)]
pub struct Author(String);
impl Author {
pub fn new(value: &str) -> Result<Self, AuthorError> {
let author = Self(String::from(value));
author.validate()?;
Ok(author)
}
pub fn to_bytes(&self) -> Vec<u8> {
hex::decode(&self.0).unwrap()
}
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
impl Display for Author {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl Human for Author {
fn display(&self) -> String {
let offset = PUBLIC_KEY_LENGTH * 2 - 6;
format!("<Author {}>", &self.0[offset..])
}
}
impl<'de> Deserialize<'de> for Author {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let public_key: String = Deserialize::deserialize(deserializer)?;
Author::new(&public_key)
.map_err(|err| serde::de::Error::custom(format!("invalid public key {}", err)))
}
}
impl From<&PublicKey> for Author {
fn from(public_key: &PublicKey) -> Self {
Self::new(&hex::encode(public_key.to_bytes())).unwrap()
}
}
impl From<&Author> for PublicKey {
fn from(author: &Author) -> Self {
PublicKey::from_bytes(&author.to_bytes()).unwrap()
}
}
impl FromStr for Author {
type Err = AuthorError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::new(s)
}
}
impl Validate for Author {
type Error = AuthorError;
fn validate(&self) -> Result<(), Self::Error> {
match hex::decode(&self.0) {
Ok(bytes) => {
if bytes.len() != PUBLIC_KEY_LENGTH {
return Err(AuthorError::InvalidLength);
}
}
Err(_) => {
return Err(AuthorError::InvalidHexEncoding);
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use ed25519_dalek::{PublicKey, PUBLIC_KEY_LENGTH};
use crate::identity::error::AuthorError;
use crate::Human;
use super::Author;
#[test]
fn validate() {
assert!(matches!(
Author::new("vzf4f58a2d89e93313f2de99604a814ezea9800of217b140e9l3a7ba59a5d98p"),
Err(AuthorError::InvalidHexEncoding)
));
assert!(matches!(
Author::new("123456789ffa"),
Err(AuthorError::InvalidLength)
));
assert!(
Author::new("7cf4f58a2d89e93313f2de99604a814ecea9800cf217b140e9c3a7ba59a5d982").is_ok()
);
}
#[test]
fn to_bytes() {
let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [
215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, 14, 225, 114,
243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26,
];
let author = Author::new(&hex::encode(public_key_bytes)).unwrap();
assert_eq!(author.to_bytes(), public_key_bytes.to_vec());
}
#[test]
fn from_public_key() {
let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [
215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, 14, 225, 114,
243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26,
];
let public_key = PublicKey::from_bytes(&public_key_bytes).unwrap();
let author: Author = (&public_key).into();
assert_eq!(author.to_string(), hex::encode(public_key_bytes));
}
#[test]
fn from_str() {
let author_str = "7cf4f58a2d89e93313f2de99604a814ecea9800cf217b140e9c3a7ba59a5d982";
let author: Author = author_str.parse().unwrap();
assert_eq!(author_str, author.as_str());
}
#[test]
fn string_representation() {
let author_str = "7cf4f58a2d89e93313f2de99604a814ecea9800cf217b140e9c3a7ba59a5d982";
let author = Author::new(author_str).unwrap();
assert_eq!(author_str, author.as_str());
assert_eq!(author_str, author.to_string());
assert_eq!(author_str, format!("{}", author));
}
#[test]
fn short_representation() {
let author_str = "7cf4f58a2d89e93313f2de99604a814ecea9800cf217b140e9c3a7ba59a5d982";
let author = Author::new(author_str).unwrap();
assert_eq!(author.display(), "<Author a5d982>");
}
}