jid: Simplify *Part parsing
Reuse the main JID parsing blocks for the separate parts.
This commit is contained in:
parent
bd17a2ffbf
commit
7e260dd677
2 changed files with 7 additions and 27 deletions
|
|
@ -16,19 +16,12 @@ pub enum Error {
|
||||||
/// Happens when the node is empty, that is the string starts with a @.
|
/// Happens when the node is empty, that is the string starts with a @.
|
||||||
NodeEmpty,
|
NodeEmpty,
|
||||||
|
|
||||||
/// Happens when there is no domain, that is either the string is empty,
|
|
||||||
/// starts with a /, or contains the @/ sequence.
|
|
||||||
DomainEmpty,
|
|
||||||
|
|
||||||
/// Happens when the resource is empty, that is the string ends with a /.
|
/// Happens when the resource is empty, that is the string ends with a /.
|
||||||
ResourceEmpty,
|
ResourceEmpty,
|
||||||
|
|
||||||
/// Happens when the localpart is longer than 1023 bytes.
|
/// Happens when the localpart is longer than 1023 bytes.
|
||||||
NodeTooLong,
|
NodeTooLong,
|
||||||
|
|
||||||
/// Happens when the domain is longer than 1023 bytes.
|
|
||||||
DomainTooLong,
|
|
||||||
|
|
||||||
/// Happens when the resource is longer than 1023 bytes.
|
/// Happens when the resource is longer than 1023 bytes.
|
||||||
ResourceTooLong,
|
ResourceTooLong,
|
||||||
|
|
||||||
|
|
@ -60,10 +53,8 @@ impl fmt::Display for Error {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt.write_str(match self {
|
fmt.write_str(match self {
|
||||||
Error::NodeEmpty => "nodepart empty despite the presence of a @",
|
Error::NodeEmpty => "nodepart empty despite the presence of a @",
|
||||||
Error::DomainEmpty => "no domain found in this JID",
|
|
||||||
Error::ResourceEmpty => "resource empty despite the presence of a /",
|
Error::ResourceEmpty => "resource empty despite the presence of a /",
|
||||||
Error::NodeTooLong => "localpart longer than 1023 bytes",
|
Error::NodeTooLong => "localpart longer than 1023 bytes",
|
||||||
Error::DomainTooLong => "domain longer than 1023 bytes",
|
|
||||||
Error::ResourceTooLong => "resource longer than 1023 bytes",
|
Error::ResourceTooLong => "resource longer than 1023 bytes",
|
||||||
Error::NodePrep => "localpart doesn’t pass nodeprep validation",
|
Error::NodePrep => "localpart doesn’t pass nodeprep validation",
|
||||||
Error::NamePrep => "domain doesn’t pass nameprep validation",
|
Error::NamePrep => "domain doesn’t pass nameprep validation",
|
||||||
|
|
|
||||||
|
|
@ -8,20 +8,10 @@ use core::str::FromStr;
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use stringprep::{nameprep, nodeprep, resourceprep};
|
|
||||||
|
|
||||||
|
use crate::{domain_check, node_check, resource_check};
|
||||||
use crate::{BareJid, Error, Jid};
|
use crate::{BareJid, Error, Jid};
|
||||||
|
|
||||||
fn length_check(len: usize, error_empty: Error, error_too_long: Error) -> Result<(), Error> {
|
|
||||||
if len == 0 {
|
|
||||||
Err(error_empty)
|
|
||||||
} else if len > 1023 {
|
|
||||||
Err(error_too_long)
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! def_part_parse_doc {
|
macro_rules! def_part_parse_doc {
|
||||||
($name:ident, $other:ident, $more:expr) => {
|
($name:ident, $other:ident, $more:expr) => {
|
||||||
concat!(
|
concat!(
|
||||||
|
|
@ -57,7 +47,7 @@ macro_rules! def_part_into_inner_doc {
|
||||||
macro_rules! def_part_types {
|
macro_rules! def_part_types {
|
||||||
(
|
(
|
||||||
$(#[$mainmeta:meta])*
|
$(#[$mainmeta:meta])*
|
||||||
pub struct $name:ident(String) use $prepfn:ident(err = $preperr:path, empty = $emptyerr:path, long = $longerr:path);
|
pub struct $name:ident(String) use $check_fn:ident();
|
||||||
|
|
||||||
$(#[$refmeta:meta])*
|
$(#[$refmeta:meta])*
|
||||||
pub struct ref $borrowed:ident(str);
|
pub struct ref $borrowed:ident(str);
|
||||||
|
|
@ -70,9 +60,8 @@ macro_rules! def_part_types {
|
||||||
impl $name {
|
impl $name {
|
||||||
#[doc = def_part_parse_doc!($name, str, "Depending on whether the contents are changed by normalisation operations, this function either returns a copy or a reference to the original data.")]
|
#[doc = def_part_parse_doc!($name, str, "Depending on whether the contents are changed by normalisation operations, this function either returns a copy or a reference to the original data.")]
|
||||||
pub fn new(s: &str) -> Result<Cow<'_, $borrowed>, Error> {
|
pub fn new(s: &str) -> Result<Cow<'_, $borrowed>, Error> {
|
||||||
let node = $prepfn(s).map_err(|_| $preperr)?;
|
let part = $check_fn(s)?;
|
||||||
length_check(node.len(), $emptyerr, $longerr)?;
|
match part {
|
||||||
match node {
|
|
||||||
Cow::Borrowed(v) => Ok(Cow::Borrowed($borrowed::from_str_unchecked(v))),
|
Cow::Borrowed(v) => Ok(Cow::Borrowed($borrowed::from_str_unchecked(v))),
|
||||||
Cow::Owned(v) => Ok(Cow::Owned(Self(v))),
|
Cow::Owned(v) => Ok(Cow::Owned(Self(v))),
|
||||||
}
|
}
|
||||||
|
|
@ -213,7 +202,7 @@ def_part_types! {
|
||||||
///
|
///
|
||||||
/// The corresponding slice type is [`NodeRef`].
|
/// The corresponding slice type is [`NodeRef`].
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub struct NodePart(String) use nodeprep(err = Error::NodePrep, empty = Error::NodeEmpty, long = Error::NodeTooLong);
|
pub struct NodePart(String) use node_check();
|
||||||
|
|
||||||
/// `str`-like type which conforms to the requirements of [`NodePart`].
|
/// `str`-like type which conforms to the requirements of [`NodePart`].
|
||||||
///
|
///
|
||||||
|
|
@ -227,7 +216,7 @@ def_part_types! {
|
||||||
/// (optional) `/` in any [`Jid`][crate::Jid], whether
|
/// (optional) `/` in any [`Jid`][crate::Jid], whether
|
||||||
/// [`BareJid`][crate::BareJid] or [`FullJid`][crate::FullJid].
|
/// [`BareJid`][crate::BareJid] or [`FullJid`][crate::FullJid].
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub struct DomainPart(String) use nameprep(err = Error::NamePrep, empty = Error::DomainEmpty, long = Error::DomainTooLong);
|
pub struct DomainPart(String) use domain_check();
|
||||||
|
|
||||||
/// `str`-like type which conforms to the requirements of [`DomainPart`].
|
/// `str`-like type which conforms to the requirements of [`DomainPart`].
|
||||||
///
|
///
|
||||||
|
|
@ -240,7 +229,7 @@ def_part_types! {
|
||||||
/// The [`ResourcePart`] is the optional part after the `/` in a
|
/// The [`ResourcePart`] is the optional part after the `/` in a
|
||||||
/// [`Jid`][crate::Jid]. It is mandatory in [`FullJid`][crate::FullJid].
|
/// [`Jid`][crate::Jid]. It is mandatory in [`FullJid`][crate::FullJid].
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub struct ResourcePart(String) use resourceprep(err = Error::ResourcePrep, empty = Error::ResourceEmpty, long = Error::ResourceTooLong);
|
pub struct ResourcePart(String) use resource_check();
|
||||||
|
|
||||||
/// `str`-like type which conforms to the requirements of
|
/// `str`-like type which conforms to the requirements of
|
||||||
/// [`ResourcePart`].
|
/// [`ResourcePart`].
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue