use crate::internal_prelude::*;
#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] #[derive(derive_more::Display, From, Into, Serialize, Deserialize)]
#[serde(try_from = "String", into = "String")]
pub struct HsNickname(Slug);
impl FromStr for HsNickname {
type Err = InvalidNickname;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::new(s.to_string())
}
}
impl KeySpecifierComponentViaDisplayFromStr for HsNickname {}
#[derive(Clone, Debug, Hash, Eq, PartialEq, Error)]
#[non_exhaustive]
#[error("Invalid syntax for hidden service nickname")]
pub struct InvalidNickname {}
impl HsNickname {
pub fn new(s: String) -> Result<HsNickname, InvalidNickname> {
Ok(Self(s.try_into().map_err(|_| InvalidNickname {})?))
}
}
impl From<HsNickname> for String {
fn from(nick: HsNickname) -> String {
nick.0.into()
}
}
impl TryFrom<String> for HsNickname {
type Error = InvalidNickname;
fn try_from(s: String) -> Result<HsNickname, InvalidNickname> {
Self::new(s)
}
}
impl AsRef<str> for HsNickname {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
impl tor_persist::state_dir::InstanceIdentity for HsNickname {
fn kind() -> &'static str {
"hss"
}
fn write_identity(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(self, f)
}
}
#[cfg(test)]
mod test {
#![allow(clippy::bool_assert_comparison)]
#![allow(clippy::clone_on_copy)]
#![allow(clippy::dbg_macro)]
#![allow(clippy::mixed_attributes_style)]
#![allow(clippy::print_stderr)]
#![allow(clippy::print_stdout)]
#![allow(clippy::single_char_pattern)]
#![allow(clippy::unwrap_used)]
#![allow(clippy::unchecked_duration_subtraction)]
#![allow(clippy::useless_vec)]
#![allow(clippy::needless_pass_by_value)]
use super::*;
#[test]
fn mk() {
assert_eq!(HsNickname::new("".into()), Err(InvalidNickname {}));
assert_eq!(HsNickname::new("-a".into()), Err(InvalidNickname {}));
assert_eq!(HsNickname::new("b.".into()), Err(InvalidNickname {}));
assert_eq!(HsNickname::new("_c".into()).unwrap().to_string(), "_c");
assert_eq!(&HsNickname::new("x".into()).unwrap().to_string(), "x");
}
#[test]
fn serde() {
#[derive(Serialize, Deserialize, Debug)]
struct T {
n: HsNickname,
}
let j = serde_json::from_str(r#"{ "n": "x" }"#).unwrap();
let t: T = serde_json::from_value(j).unwrap();
assert_eq!(&t.n.to_string(), "x");
assert_eq!(&serde_json::to_string(&t).unwrap(), r#"{"n":"x"}"#);
let j = serde_json::from_str(r#"{ "n": "!" }"#).unwrap();
let e = serde_json::from_value::<T>(j).unwrap_err();
assert!(e.to_string().contains("Invalid syntax"), "wrong msg {e:?}");
}
#[test]
fn empty_nickname() {
assert_eq!(
HsNickname::new("".to_string()).unwrap_err(),
InvalidNickname {}
);
assert_eq!(
HsNickname::try_from("".to_string()).unwrap_err(),
InvalidNickname {}
);
assert_eq!(HsNickname::from_str("").unwrap_err(), InvalidNickname {});
}
}