use std::convert::TryFrom;
use std::fmt::Display;
use std::hash::Hash as StdHash;
use std::str::FromStr;
use ed25519_dalek::{PublicKey, PUBLIC_KEY_LENGTH};
use serde::{Deserialize, Serialize};
use crate::identity::AuthorError;
use crate::Validate;
#[derive(Clone, Debug, Serialize, Eq, StdHash, Deserialize, 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 as_str(&self) -> &str {
self.0.as_str()
}
pub fn short_str(&self) -> &str {
let offset = self.0.len() - 6;
&self.0[offset..]
}
}
impl Display for Author {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<Author {}>", self.short_str())
}
}
impl TryFrom<PublicKey> for Author {
type Error = AuthorError;
fn try_from(public_key: PublicKey) -> Result<Self, Self::Error> {
Self::new(&hex::encode(public_key.to_bytes()))
}
}
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 super::Author;
#[test]
fn validate() {
assert!(Author::new("abcdefg").is_err());
assert!(Author::new("112233445566ff").is_err());
assert!(
Author::new("7cf4f58a2d89e93313f2de99604a814ecea9800cf217b140e9c3a7ba59a5d982").is_ok()
);
}
#[test]
fn string_conversion() {
let author_str = "7cf4f58a2d89e93313f2de99604a814ecea9800cf217b140e9c3a7ba59a5d982";
let author: Author = author_str.parse().unwrap();
assert_eq!(author_str, author.as_str());
assert_eq!(format!("{}", author), "<Author a5d982>");
}
}