use std::borrow::Borrow;
use std::convert::{Into, TryFrom};
use std::marker::PhantomData;
use std::{cmp, fmt, hash, ops};
use unsigned_varint::{decode as varint_decode, encode as varint_encode};
use crate::errors::{DecodeError, DecodeOwnedError};
use crate::hashes::Code;
use crate::storage::Storage;
pub type Multihash = MultihashGeneric<Code>;
pub type MultihashRef<'a> = MultihashRefGeneric<'a, Code>;
pub type BoxedMultihashDigest<T = Code> = Box<dyn MultihashDigest<T>>;
#[derive(Clone)]
pub struct MultihashGeneric<T: TryFrom<u64>> {
storage: Storage,
_code: PhantomData<T>,
}
impl<T: TryFrom<u64>> fmt::Debug for MultihashGeneric<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Multihash").field(&self.as_bytes()).finish()
}
}
impl<T: TryFrom<u64>> PartialEq for MultihashGeneric<T> {
fn eq(&self, other: &Self) -> bool {
self.storage.bytes() == other.storage.bytes()
}
}
impl<T: TryFrom<u64>> Eq for MultihashGeneric<T> {}
impl<T: TryFrom<u64>> hash::Hash for MultihashGeneric<T> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.storage.bytes().hash(state);
}
}
impl<T: TryFrom<u64>> MultihashGeneric<T> {
pub fn from_bytes(bytes: Vec<u8>) -> Result<MultihashGeneric<T>, DecodeOwnedError> {
if let Err(err) = MultihashRefGeneric::<T>::from_slice(&bytes) {
return Err(DecodeOwnedError {
error: err,
data: bytes,
});
}
Ok(Self {
storage: Storage::from_slice(&bytes),
_code: PhantomData,
})
}
pub fn into_bytes(self) -> Vec<u8> {
self.to_vec()
}
pub fn to_vec(&self) -> Vec<u8> {
Vec::from(self.as_bytes())
}
pub fn as_bytes(&self) -> &[u8] {
self.storage.bytes()
}
pub fn as_ref(&self) -> MultihashRefGeneric<T> {
MultihashRefGeneric {
bytes: self.as_bytes(),
_code: PhantomData,
}
}
pub fn algorithm(&self) -> T {
self.as_ref().algorithm()
}
pub fn digest(&self) -> &[u8] {
self.as_ref().digest()
}
}
impl<T: TryFrom<u64>> AsRef<[u8]> for MultihashGeneric<T> {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl<T: TryFrom<u64>> ops::Deref for MultihashGeneric<T> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.as_bytes()
}
}
impl<T: TryFrom<u64>> Borrow<[u8]> for MultihashGeneric<T> {
fn borrow(&self) -> &[u8] {
self.as_bytes()
}
}
impl<'a, T: TryFrom<u64>> PartialEq<MultihashRefGeneric<'a, T>> for MultihashGeneric<T> {
fn eq(&self, other: &MultihashRefGeneric<'a, T>) -> bool {
&*self.as_bytes() == other.as_bytes()
}
}
impl<T: TryFrom<u64>> TryFrom<Vec<u8>> for MultihashGeneric<T> {
type Error = DecodeOwnedError;
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
MultihashGeneric::from_bytes(value)
}
}
impl<T: TryFrom<u64>> Into<Vec<u8>> for MultihashGeneric<T> {
fn into(self) -> Vec<u8> {
self.to_vec()
}
}
impl<T: TryFrom<u64>> PartialOrd for MultihashGeneric<T> {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<T: TryFrom<u64>> Ord for MultihashGeneric<T> {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.as_ref().cmp(&other.as_ref())
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MultihashRefGeneric<'a, T> {
bytes: &'a [u8],
_code: PhantomData<T>,
}
impl<'a, T: TryFrom<u64>> MultihashRefGeneric<'a, T> {
pub fn from_slice(input: &'a [u8]) -> Result<Self, DecodeError> {
if input.is_empty() {
return Err(DecodeError::BadInputLength);
}
let (code, bytes) = varint_decode::u64(&input).map_err(|_| DecodeError::BadInputLength)?;
T::try_from(code).map_err(|_| DecodeError::UnknownCode)?;
let (hash_len, bytes) =
varint_decode::u64(&bytes).map_err(|_| DecodeError::BadInputLength)?;
if (bytes.len() as u64) != hash_len {
return Err(DecodeError::BadInputLength);
}
Ok(Self {
bytes: input,
_code: PhantomData,
})
}
pub fn algorithm(&self) -> T {
let (rawcode, _bytes) =
varint_decode::u64(&self.bytes).expect("multihash is known to be valid algorithm");
T::try_from(rawcode)
.unwrap_or_else(|_| panic!("Should not occur as multihash is known to be valid"))
}
pub fn digest(&self) -> &'a [u8] {
let (_code, bytes) =
varint_decode::u64(&self.bytes).expect("multihash is known to be valid digest");
let (_hash_len, bytes) =
varint_decode::u64(&bytes).expect("multihash is known to be a valid digest");
&bytes[..]
}
pub fn to_owned(&self) -> MultihashGeneric<T> {
MultihashGeneric {
storage: Storage::from_slice(self.bytes),
_code: PhantomData,
}
}
pub fn as_bytes(&self) -> &'a [u8] {
&self.bytes
}
}
impl<'a, T: TryFrom<u64>> PartialEq<MultihashGeneric<T>> for MultihashRefGeneric<'a, T> {
fn eq(&self, other: &MultihashGeneric<T>) -> bool {
self.as_bytes() == &*other.as_bytes()
}
}
impl<'a, T: TryFrom<u64>> ops::Deref for MultihashRefGeneric<'a, T> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.as_bytes()
}
}
impl<'a, T: TryFrom<u64>> Into<Vec<u8>> for MultihashRefGeneric<'a, T> {
fn into(self) -> Vec<u8> {
self.to_vec()
}
}
pub trait Multihasher<T: TryFrom<u64> + Copy> {
const CODE: T;
fn digest(data: &[u8]) -> MultihashGeneric<T>;
}
pub trait MultihashDigest<T: TryFrom<u64>> {
fn code(&self) -> T;
fn digest(&self, data: &[u8]) -> MultihashGeneric<T>;
fn input(&mut self, data: &[u8]);
fn result(self) -> MultihashGeneric<T>;
fn result_reset(&mut self) -> MultihashGeneric<T>;
fn reset(&mut self);
}
pub fn wrap<T: Into<u64> + TryFrom<u64>>(code: T, data: &[u8]) -> MultihashGeneric<T> {
let mut code_buf = varint_encode::u64_buffer();
let code = varint_encode::u64(code.into(), &mut code_buf);
let mut size_buf = varint_encode::u64_buffer();
let size = varint_encode::u64(data.len() as u64, &mut size_buf);
MultihashGeneric {
storage: Storage::from_slices(&[code, &size, &data]),
_code: PhantomData,
}
}