use std::fmt::{Display, Formatter}; use std::str::FromStr; use secrecy::{CloneableSecret, DebugSecret, SerializableSecret, Zeroize}; use serde::{Deserialize, Serialize}; use crate::operation::GiteratedObject; use super::instance::Instance; /// A user, defined by its username and instance. /// /// # Textual Format /// A user's textual reference is defined as: /// /// `{username: String}:{instance: Instance}` /// /// # Examples /// For the user with the username `barson` and the instance `giterated.dev`, /// the following [`User`] initialization would be valid: /// /// ``` /// let user = User { /// username: String::from("barson"), /// instance: Instance::from_str("giterated.dev").unwrap() /// }; /// /// // This is correct /// assert_eq!(User::from_str("barson:giterated.dev").unwrap(), user); /// ``` #[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] pub struct User { pub username: String, pub instance: Instance, } impl GiteratedObject for User { fn object_name(&self) -> &str { "user" } fn from_object_str(object_str: &str) -> Result { Ok(User::from_str(object_str).unwrap()) } } impl Display for User { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}:{}", self.username, self.instance.url) } } impl From for User { fn from(user_string: String) -> Self { User::from_str(&user_string).unwrap() } } impl FromStr for User { type Err = (); fn from_str(s: &str) -> Result { let mut colon_split = s.split(':'); let username = colon_split.next().unwrap().to_string(); let instance = Instance::from_str(colon_split.next().unwrap()).unwrap(); Ok(Self { username, instance }) } } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Password(pub String); impl Zeroize for Password { fn zeroize(&mut self) { self.0.zeroize() } } impl SerializableSecret for Password {} impl CloneableSecret for Password {} impl DebugSecret for Password {}