use litep2p::types::multihash::{
Code as LiteP2pCode, Error as LiteP2pError, Multihash as LiteP2pMultihash, MultihashDigest as _,
};
use std::fmt::{self, Debug};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Code {
Identity,
Sha2_256,
}
impl Code {
pub fn digest(&self, input: &[u8]) -> Multihash {
LiteP2pCode::from(*self).digest(input).into()
}
}
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("invalid multihash size '{0}'")]
InvalidSize(u64),
#[error("unsupported multihash code '{0:x}'")]
UnsupportedCode(u64),
#[error("other error: {0}")]
Other(Box<dyn std::error::Error + Send + Sync>),
}
impl From<LiteP2pError> for Error {
fn from(error: LiteP2pError) -> Self {
match error {
LiteP2pError::InvalidSize(s) => Self::InvalidSize(s),
LiteP2pError::UnsupportedCode(c) => Self::UnsupportedCode(c),
e => Self::Other(Box::new(e)),
}
}
}
impl From<Code> for LiteP2pCode {
fn from(code: Code) -> Self {
match code {
Code::Identity => LiteP2pCode::Identity,
Code::Sha2_256 => LiteP2pCode::Sha2_256,
}
}
}
impl TryFrom<LiteP2pCode> for Code {
type Error = Error;
fn try_from(code: LiteP2pCode) -> Result<Self, Self::Error> {
match code {
LiteP2pCode::Identity => Ok(Code::Identity),
LiteP2pCode::Sha2_256 => Ok(Code::Sha2_256),
_ => Err(Error::UnsupportedCode(code.into())),
}
}
}
impl TryFrom<u64> for Code {
type Error = Error;
fn try_from(code: u64) -> Result<Self, Self::Error> {
match LiteP2pCode::try_from(code) {
Ok(code) => code.try_into(),
Err(e) => Err(e.into()),
}
}
}
impl From<Code> for u64 {
fn from(code: Code) -> Self {
LiteP2pCode::from(code).into()
}
}
#[derive(Clone, Copy, Hash, PartialEq, Eq, Ord, PartialOrd)]
pub struct Multihash {
multihash: LiteP2pMultihash,
}
impl Multihash {
pub fn code(&self) -> u64 {
self.multihash.code()
}
pub fn digest(&self) -> &[u8] {
self.multihash.digest()
}
pub fn wrap(code: u64, input_digest: &[u8]) -> Result<Self, Error> {
LiteP2pMultihash::wrap(code, input_digest).map(Into::into).map_err(Into::into)
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
LiteP2pMultihash::from_bytes(bytes).map(Into::into).map_err(Into::into)
}
pub fn to_bytes(&self) -> Vec<u8> {
self.multihash.to_bytes()
}
}
impl Debug for Multihash {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt(&self.multihash, f)
}
}
impl From<LiteP2pMultihash> for Multihash {
fn from(multihash: LiteP2pMultihash) -> Self {
Multihash { multihash }
}
}
impl From<Multihash> for LiteP2pMultihash {
fn from(multihash: Multihash) -> Self {
multihash.multihash
}
}
impl From<multihash::Multihash<64>> for Multihash {
fn from(generic: multihash::Multihash<64>) -> Self {
LiteP2pMultihash::wrap(generic.code(), generic.digest())
.expect("both have size 64; qed")
.into()
}
}
impl From<Multihash> for multihash::Multihash<64> {
fn from(multihash: Multihash) -> Self {
multihash::Multihash::<64>::wrap(multihash.code(), multihash.digest())
.expect("both have size 64; qed")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn code_from_u64() {
assert_eq!(Code::try_from(0x00).unwrap(), Code::Identity);
assert_eq!(Code::try_from(0x12).unwrap(), Code::Sha2_256);
assert!(matches!(Code::try_from(0x01).unwrap_err(), Error::UnsupportedCode(0x01)));
}
#[test]
fn code_into_u64() {
assert_eq!(u64::from(Code::Identity), 0x00);
assert_eq!(u64::from(Code::Sha2_256), 0x12);
}
}