use crate::{Error, Result};
use core::{
fmt::{self, Display},
str::FromStr,
};
#[cfg(feature = "password-hash")]
use password_hash::Ident;
#[cfg(feature = "password-hash")]
#[cfg_attr(docsrs, doc(cfg(feature = "password-hash")))]
pub const ARGON2D_IDENT: Ident<'_> = Ident::new_unwrap("argon2d");
#[cfg(feature = "password-hash")]
#[cfg_attr(docsrs, doc(cfg(feature = "password-hash")))]
pub const ARGON2I_IDENT: Ident<'_> = Ident::new_unwrap("argon2i");
#[cfg(feature = "password-hash")]
#[cfg_attr(docsrs, doc(cfg(feature = "password-hash")))]
pub const ARGON2ID_IDENT: Ident<'_> = Ident::new_unwrap("argon2id");
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Default, Ord)]
pub enum Algorithm {
Argon2d = 0,
Argon2i = 1,
#[default]
Argon2id = 2,
}
impl Algorithm {
pub fn new(id: impl AsRef<str>) -> Result<Self> {
id.as_ref().parse()
}
pub const fn as_str(&self) -> &'static str {
match self {
Algorithm::Argon2d => "argon2d",
Algorithm::Argon2i => "argon2i",
Algorithm::Argon2id => "argon2id",
}
}
#[cfg(feature = "password-hash")]
#[cfg_attr(docsrs, doc(cfg(feature = "password-hash")))]
pub const fn ident(&self) -> Ident<'static> {
match self {
Algorithm::Argon2d => ARGON2D_IDENT,
Algorithm::Argon2i => ARGON2I_IDENT,
Algorithm::Argon2id => ARGON2ID_IDENT,
}
}
pub(crate) const fn to_le_bytes(self) -> [u8; 4] {
(self as u32).to_le_bytes()
}
}
impl AsRef<str> for Algorithm {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl Display for Algorithm {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl FromStr for Algorithm {
type Err = Error;
fn from_str(s: &str) -> Result<Algorithm> {
match s {
"argon2d" => Ok(Algorithm::Argon2d),
"argon2i" => Ok(Algorithm::Argon2i),
"argon2id" => Ok(Algorithm::Argon2id),
_ => Err(Error::AlgorithmInvalid),
}
}
}
#[cfg(feature = "password-hash")]
#[cfg_attr(docsrs, doc(cfg(feature = "password-hash")))]
impl From<Algorithm> for Ident<'static> {
fn from(alg: Algorithm) -> Ident<'static> {
alg.ident()
}
}
#[cfg(feature = "password-hash")]
#[cfg_attr(docsrs, doc(cfg(feature = "password-hash")))]
impl<'a> TryFrom<Ident<'a>> for Algorithm {
type Error = password_hash::Error;
fn try_from(ident: Ident<'a>) -> password_hash::Result<Algorithm> {
match ident {
ARGON2D_IDENT => Ok(Algorithm::Argon2d),
ARGON2I_IDENT => Ok(Algorithm::Argon2i),
ARGON2ID_IDENT => Ok(Algorithm::Argon2id),
_ => Err(password_hash::Error::Algorithm),
}
}
}