identifiers: Generate public parse functions for opaque ID types with invariants

This commit is contained in:
Jonas Platte 2021-11-26 20:57:47 +01:00
parent 87194d5bf9
commit 6324034f03
No known key found for this signature in database
GPG Key ID: CC154DE0E30B7C67
2 changed files with 23 additions and 13 deletions

View File

@ -201,6 +201,24 @@ macro_rules! opaque_identifier {
macro_rules! opaque_identifier_validated { macro_rules! opaque_identifier_validated {
($id:ident, $validate_id:expr) => { ($id:ident, $validate_id:expr) => {
impl $id {
#[rustfmt::skip]
doc_concat! {
#[doc = concat!("\
Try parsing a `&str` into a `Box<", stringify!($id), ">`.\n\
\n\
The same can also be done using `FromStr`, `TryFrom` or `TryInto`.\n\
This function is simply more constrained and thus useful in generic contexts.\
")]
pub fn parse(
s: impl AsRef<str> + Into<Box<str>>,
) -> Result<Box<Self>, crate::Error> {
$validate_id(s.as_ref())?;
Ok($id::from_owned(s.into()))
}
}
}
opaque_identifier_common_impls!($id); opaque_identifier_common_impls!($id);
impl From<Box<$id>> for String { impl From<Box<$id>> for String {
@ -219,21 +237,13 @@ macro_rules! opaque_identifier_validated {
let s = String::deserialize(deserializer)?; let s = String::deserialize(deserializer)?;
match try_from(s) { match $id::parse(s) {
Ok(o) => Ok(o), Ok(o) => Ok(o),
Err(e) => Err(D::Error::custom(e)), Err(e) => Err(D::Error::custom(e)),
} }
} }
} }
fn try_from<S>(s: S) -> Result<Box<$id>, crate::Error>
where
S: AsRef<str> + Into<Box<str>>,
{
$validate_id(s.as_ref())?;
Ok($id::from_owned(s.into()))
}
impl<'a> std::convert::TryFrom<&'a str> for &'a $id { impl<'a> std::convert::TryFrom<&'a str> for &'a $id {
type Error = crate::Error; type Error = crate::Error;
@ -247,7 +257,7 @@ macro_rules! opaque_identifier_validated {
type Err = crate::Error; type Err = crate::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
try_from(s) $id::parse(s)
} }
} }
@ -255,7 +265,7 @@ macro_rules! opaque_identifier_validated {
type Error = crate::Error; type Error = crate::Error;
fn try_from(s: &str) -> Result<Self, Self::Error> { fn try_from(s: &str) -> Result<Self, Self::Error> {
try_from(s) $id::parse(s)
} }
} }
@ -263,7 +273,7 @@ macro_rules! opaque_identifier_validated {
type Error = crate::Error; type Error = crate::Error;
fn try_from(s: String) -> Result<Self, Self::Error> { fn try_from(s: String) -> Result<Self, Self::Error> {
try_from(s) $id::parse(s)
} }
} }
}; };

View File

@ -45,7 +45,7 @@ impl UserId {
let id_str = id.as_ref(); let id_str = id.as_ref();
if id_str.starts_with('@') { if id_str.starts_with('@') {
try_from(id) Self::parse(id)
} else { } else {
Ok(Self::from_owned(format!("@{}:{}", id_str, server_name).into())) Ok(Self::from_owned(format!("@{}:{}", id_str, server_name).into()))
} }