use std::fmt::Display;
use salvo::oapi::ToSchema;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash, ToSchema, Debug)]
#[serde(untagged)]
#[allow(clippy::exhaustive_enums)]
pub enum Uid {
I64(i64),
Str(String),
}
impl From<i64> for Uid {
fn from(value: i64) -> Self {
Self::I64(value)
}
}
impl From<String> for Uid {
fn from(value: String) -> Self {
Self::Str(value)
}
}
impl From<&str> for Uid {
fn from(value: &str) -> Self {
Self::Str(value.to_owned())
}
}
impl Display for Uid {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self {
Uid::I64(v) => write!(f, "{v}"),
Uid::Str(v) => write!(f, "{v}"),
}
}
}
impl Uid {
pub const fn is_i64_item(&self) -> bool {
if let Self::I64(_) = self {
return true;
}
false
}
pub const fn to_i64_item(&self) -> Option<i64> {
if let Self::I64(v) = self {
return Some(*v);
}
None
}
pub const fn to_i64_or_default(&self) -> i64 {
if let Self::I64(v) = self {
return *v;
}
0
}
pub const fn is_str_item(&self) -> bool {
if let Self::Str(_) = self {
return true;
}
false
}
pub fn into_str_item(self) -> Option<String> {
if let Self::Str(v) = self {
return Some(v);
}
None
}
pub fn into_str_or_default(self) -> String {
if let Self::Str(v) = self {
return v;
}
String::new()
}
pub const fn as_str_item(&self) -> Option<&String> {
if let Self::Str(v) = self {
return Some(v);
}
None
}
}
#[allow(non_camel_case_types)]
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash, ToSchema, Debug)]
#[serde(tag = "identifier_type", content = "identifier_value")]
pub enum UserIdentifier {
id(Uid),
username(String),
email(String),
phone(String),
}
impl UserIdentifier {
pub const fn is_id(&self) -> bool {
if let Self::id(_) = self {
return true;
}
false
}
pub const fn is_username(&self) -> bool {
if let Self::username(_) = self {
return true;
}
false
}
pub const fn is_email(&self) -> bool {
if let Self::email(_) = self {
return true;
}
false
}
pub const fn is_phone(&self) -> bool {
if let Self::phone(_) = self {
return true;
}
false
}
pub const fn id(&self) -> Option<&Uid> {
if let Self::id(id) = self {
return Some(id);
}
None
}
pub fn into_username(self) -> Option<String> {
if let Self::username(username) = self {
return Some(username);
}
None
}
pub fn into_email(self) -> Option<String> {
if let Self::email(email) = self {
return Some(email);
}
None
}
pub fn into_phone(self) -> Option<String> {
if let Self::phone(phone) = self {
return Some(phone);
}
None
}
pub const fn as_username(&self) -> Option<&String> {
if let Self::username(username) = self {
return Some(username);
}
None
}
pub const fn as_email(&self) -> Option<&String> {
if let Self::email(email) = self {
return Some(email);
}
None
}
pub const fn as_phone(&self) -> Option<&String> {
if let Self::phone(phone) = self {
return Some(phone);
}
None
}
}
#[cfg(test)]
mod tests {
use super::UserIdentifier;
#[test]
fn test_json() {
assert_eq!(
r##"{"identifier_type":"id","identifier_value":"a"}"##,
serde_json::to_string(&UserIdentifier::id("a".into())).unwrap()
);
assert_eq!(
r##"{"identifier_type":"id","identifier_value":1}"##,
serde_json::to_string(&UserIdentifier::id(1.into())).unwrap()
);
}
}