pub use crate::{Hash, OUTPUT_SIZE};
impl serde::Serialize for Hash {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_bytes(&self.to_bytes())
}
}
impl<'de> serde::Deserialize<'de> for Hash {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::{Unexpected, Visitor};
struct BV;
impl<'v> Visitor<'v> for BV {
type Value = [u8; OUTPUT_SIZE];
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "{OUTPUT_SIZE} bytes")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
v.try_into()
.map_err(|_| serde::de::Error::invalid_length(v.len(), &self))
}
}
let bytes = deserializer.deserialize_bytes(BV)?;
Hash::try_from(&bytes).map_err(|_| {
serde::de::Error::invalid_value(
Unexpected::Unsigned(u32::from_be_bytes(bytes[12..16].try_into().unwrap()) as u64),
&"a valid argon2id version",
)
})
}
}
#[cfg(feature = "base64")]
pub mod base64 {
use serde::de::{Unexpected, Visitor};
use serde::{Deserializer, Serializer};
use super::*;
use crate::base64::BASE64;
use crate::{BASE64_OUTPUT_SIZE, ParseError};
pub fn serialize<S>(value: Hash, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut buf = [0u8; BASE64_OUTPUT_SIZE];
serializer.serialize_str(value.write_base64(&mut buf))
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Hash, D::Error>
where
D: Deserializer<'de>,
{
struct B64Visitor;
impl<'v> Visitor<'v> for B64Visitor {
type Value = [u8; OUTPUT_SIZE];
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "a base64 string of length {BASE64_OUTPUT_SIZE}")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
if v.len() != BASE64_OUTPUT_SIZE {
return Err(serde::de::Error::invalid_length(v.len(), &self));
}
let mut buf = [0u8; OUTPUT_SIZE];
::base64::Engine::decode_slice(&BASE64, v, &mut buf)
.map_err(|_| serde::de::Error::invalid_value(Unexpected::Str(v), &self))?;
Ok(buf)
}
}
let bytes = deserializer.deserialize_str(B64Visitor)?;
Hash::try_from(&bytes).map_err(|err| match err {
ParseError::InvalidVersion(v) => serde::de::Error::invalid_value(
Unexpected::Unsigned(v as u64),
&"a valid argon2 version",
),
ParseError::MemoryTooLow { .. } | ParseError::InvalidParameters => {
serde::de::Error::invalid_value(
Unexpected::Other("parameters"),
&"valid argon2 parameters",
)
},
ParseError::SliceLength => unreachable!(),
})
}
}