1use std::{
4 borrow::Cow,
5 fmt::{Display, Formatter},
6};
7
8#[cfg(feature = "arbitrary")]
9use arbitrary::Arbitrary;
10#[cfg(feature = "bounded-static")]
11use bounded_static::ToStatic;
12#[cfg(feature = "serde")]
13use serde::{Deserialize, Serialize};
14
15use crate::{
16 core::{impl_try_from, Atom},
17 secret::Secret,
18};
19
20#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
22#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
23#[derive(Debug, Clone, PartialEq, Eq, Hash)]
24#[non_exhaustive]
25pub enum AuthMechanism<'a> {
26 Plain,
40
41 Login,
56
57 XOAuth2,
71
72 Other(AuthMechanismOther<'a>),
74}
75
76impl_try_from!(Atom<'a>, 'a, &'a [u8], AuthMechanism<'a>);
77impl_try_from!(Atom<'a>, 'a, Vec<u8>, AuthMechanism<'a>);
78impl_try_from!(Atom<'a>, 'a, &'a str, AuthMechanism<'a>);
79impl_try_from!(Atom<'a>, 'a, String, AuthMechanism<'a>);
80impl_try_from!(Atom<'a>, 'a, Cow<'a, str>, AuthMechanism<'a>);
81
82impl<'a> From<Atom<'a>> for AuthMechanism<'a> {
83 fn from(atom: Atom<'a>) -> Self {
84 match atom.as_ref().to_ascii_uppercase().as_str() {
85 "PLAIN" => Self::Plain,
86 "LOGIN" => Self::Login,
87 "XOAUTH2" => Self::XOAuth2,
88 _ => Self::Other(AuthMechanismOther(atom)),
89 }
90 }
91}
92
93impl<'a> Display for AuthMechanism<'a> {
94 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
95 f.write_str(match self {
96 Self::Plain => "PLAIN",
97 Self::Login => "LOGIN",
98 Self::XOAuth2 => "XOAUTH2",
99 Self::Other(other) => other.0.as_ref(),
100 })
101 }
102}
103
104#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
108#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
109#[derive(Debug, Clone, PartialEq, Eq, Hash)]
110pub struct AuthMechanismOther<'a>(Atom<'a>);
111
112#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
116#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
117#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
118#[derive(Debug, Clone, PartialEq, Eq, Hash)]
119pub struct AuthenticateData(pub Secret<Vec<u8>>);
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn test_conversion() {
127 assert!(AuthMechanism::try_from("plain").is_ok());
128 assert!(AuthMechanism::try_from("login").is_ok());
129 assert!(AuthMechanism::try_from("xoauth2").is_ok());
130 assert!(AuthMechanism::try_from("xxxplain").is_ok());
131 assert!(AuthMechanism::try_from("xxxlogin").is_ok());
132 assert!(AuthMechanism::try_from("xxxxoauth2").is_ok());
133 }
134}