use blake2::Blake2b512;
use blake2::Digest;
use rusqlite::types::FromSql;
use rusqlite::types::FromSqlError;
use rusqlite::types::FromSqlResult;
use rusqlite::types::ToSql;
use rusqlite::types::ToSqlOutput;
use rusqlite::types::ValueRef;
use thiserror::Error;
use std::ops::Deref;
use std::ops::DerefMut;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Blake2b512Digest(Box<[u8; 64]>);
impl Deref for Blake2b512Digest {
type Target = [u8; 64];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Blake2b512Digest {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl From<Blake2b512Digest> for Box<[u8]> {
fn from(value: Blake2b512Digest) -> Self {
Box::new(*value)
}
}
impl From<Blake2b512> for Blake2b512Digest {
fn from(value: Blake2b512) -> Self {
let mut buffer: [u8; 64] = [0; 64];
value.finalize_into((&mut buffer).into());
return Self(Box::new(buffer));
}
}
impl TryFrom<Box<[u8]>> for Blake2b512Digest {
type Error = Blake2b512BlobLengthMismatch;
fn try_from(value: Box<[u8]>) -> Result<Self, Self::Error> {
let size = value.len();
Ok(Self(value.try_into().map_err(|_| Blake2b512BlobLengthMismatch{ got: size })?))
}
}
impl TryFrom<&[u8]> for Blake2b512Digest {
type Error = Blake2b512BlobLengthMismatch;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
let size = value.len();
Ok(Self(Box::new(value.try_into().map_err(|_| Blake2b512BlobLengthMismatch{ got: size })?)))
}
}
#[derive(Debug, Clone, Error)]
#[error("Problem reading Blake2b512 hash: exepected 64 bytes, got {got} bytes")]
pub struct Blake2b512BlobLengthMismatch {
got: usize
}
impl FromSql for Blake2b512Digest {
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_blob()?
.try_into()
.map_err(|e: Blake2b512BlobLengthMismatch| FromSqlError::InvalidBlobSize {
expected_size: 64,
blob_size: e.got
})
}
}
impl ToSql for Blake2b512Digest {
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
Ok(ToSqlOutput::Borrowed(ValueRef::Blob(self.deref())))
}
}