use std::{marker::PhantomData};
use litl::{Litl, impl_debug_as_litl};
use serde::{Serialize, Deserializer, Serializer};
use serde_derive::{Serialize, Deserialize};
#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename = "Conundrum/Hash:Blake3")]
pub struct RawHash(
#[serde(deserialize_with="deserialize_blake3")]
#[serde(serialize_with="serialize_blake3")]
blake3::Hash
);
impl_debug_as_litl!(RawHash);
use crate::serde_bytes_array;
fn deserialize_blake3<'de, D>(de: D) -> Result<blake3::Hash, D::Error> where D: Deserializer<'de> {
let bytes: [u8; 32] = serde_bytes_array::deserialize(de)?;
Ok(blake3::Hash::from(bytes))
}
fn serialize_blake3<S>(hash: &blake3::Hash, se: S) -> Result<S::Ok, S::Error> where S: Serializer {
serde_bytes::Bytes::new(hash.as_bytes()).serialize(se)
}
impl Ord for RawHash {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.as_bytes().cmp(other.as_bytes())
}
}
impl PartialOrd for RawHash {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl RawHash {
pub fn as_bytes(&self) -> &[u8] {
self.0.as_bytes()
}
}
#[derive(Clone, Default)]
pub struct RawHasher(blake3::Hasher);
impl RawHasher {
pub fn update(&mut self, data: &[u8]) -> &mut Self {
self.0.update(data);
self
}
pub fn finalize(&mut self) -> RawHash {
RawHash(self.0.finalize())
}
}
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
pub struct HashOf<T> {
hash: RawHash,
#[serde(default)]
_marker: PhantomData<T>,
}
impl<T: Serialize> HashOf<T> {
pub fn hash(value: &T) -> Self {
HashOf {
hash: RawHasher::default()
.update(&Litl::write_from(value))
.finalize(),
_marker: PhantomData,
}
}
}
impl<T> PartialEq for HashOf<T> {
fn eq(&self, other: &Self) -> bool {
self.hash.eq(&other.hash)
}
}
impl<T> Eq for HashOf<T> {}
impl<T> Ord for HashOf<T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.hash.cmp(&other.hash)
}
}
impl<T> PartialOrd for HashOf<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<T> std::hash::Hash for HashOf<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.hash.hash(state)
}
}
impl<T> std::fmt::Debug for HashOf<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.hash.fmt(f)
}
}
impl<T> Clone for HashOf<T> {
fn clone(&self) -> Self {
Self {
hash: self.hash,
_marker: PhantomData,
}
}
}
impl<T> Copy for HashOf<T> {}