use core::{borrow::Borrow, fmt, iter};
#[inline]
pub fn get_components(v: &str) -> impl Iterator<Item = NamespaceComponent<'_>> {
let mut component_iterator = v.split("::").peekable();
if component_iterator.peek() == Some(&"") {
let _ = component_iterator.next();
}
component_iterator.map(|valid_component| {
unsafe { NamespaceComponent::new_unchecked(valid_component) }
})
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
pub enum NotSingleComponentError {
NoComponents,
MultipleComponents,
}
impl core::error::Error for NotSingleComponentError {}
impl core::fmt::Display for NotSingleComponentError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::MultipleComponents => f.write_str("invalid single-namespace-component string, containing more than one `::`-delimited components"),
Self::NoComponents => f.write_str("invalid single-namespace-component string: contains no components (probably empty)")
}
}
}
#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
pub struct NamespaceComponent<'s>(&'s str);
impl<'s> NamespaceComponent<'s> {
#[inline]
pub const unsafe fn new_unchecked(raw_component: &'s str) -> Self {
Self(raw_component)
}
#[inline]
pub fn new(raw_component: &'s str) -> Result<Self, NotSingleComponentError> {
let raw_component = raw_component.strip_prefix("::").unwrap_or(raw_component);
if raw_component.contains("::") {
Err(NotSingleComponentError::MultipleComponents)
} else {
Ok(unsafe { Self::new_unchecked(raw_component) })
}
}
#[must_use]
#[inline]
pub const fn as_str(&self) -> &'s str {
self.0
}
#[must_use]
#[inline]
pub const fn len(&self) -> usize {
self.as_str().len()
}
#[must_use]
#[inline]
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
#[cfg(any(feature = "std", test))]
#[must_use]
#[inline]
pub fn as_os_str(&self) -> &std::ffi::OsStr {
std::ffi::OsStr::new(self.as_str())
}
}
impl Borrow<str> for NamespaceComponent<'_> {
#[inline]
fn borrow(&self) -> &str {
self.as_str()
}
}
impl AsRef<str> for NamespaceComponent<'_> {
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl fmt::Display for NamespaceComponent<'_> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl<'s> TryFrom<&'s str> for NamespaceComponent<'s> {
type Error = NotSingleComponentError;
#[inline]
fn try_from(value: &'s str) -> Result<Self, Self::Error> {
Self::new(value)
}
}
impl<'s> From<NamespaceComponent<'s>> for &'s str {
#[inline]
fn from(value: NamespaceComponent<'s>) -> Self {
value.as_str()
}
}
impl crate::NamespacePath for NamespaceComponent<'_> {
#[inline(always)]
fn components(&self) -> impl IntoIterator<Item = NamespaceComponent<'_>> {
iter::once(*self)
}
#[inline(always)]
fn components_hint(&self) -> crate::path::NamespaceComponentsHint {
crate::path::NamespaceComponentsHint::single(*self)
}
}
macro_rules! impl_eq_ord {
($lhs:ty, $rhs:ty) => {
impl PartialEq<$rhs> for $lhs {
#[inline]
fn eq(&self, rhs: &$rhs) -> bool {
PartialEq::eq(self.as_str(), &rhs[..])
}
#[allow(clippy::partialeq_ne_impl)]
#[inline]
fn ne(&self, rhs: &$rhs) -> bool {
PartialEq::ne(self.as_str(), &rhs[..])
}
}
impl PartialOrd<$rhs> for $lhs {
#[inline]
fn partial_cmp(&self, rhs: &$rhs) -> Option<core::cmp::Ordering> {
PartialOrd::partial_cmp(self.as_str(), &rhs[..])
}
#[inline]
fn lt(&self, rhs: &$rhs) -> bool {
PartialOrd::lt(self.as_str(), &rhs[..])
}
#[inline]
fn le(&self, rhs: &$rhs) -> bool {
PartialOrd::le(self.as_str(), &rhs[..])
}
#[inline]
fn gt(&self, rhs: &$rhs) -> bool {
PartialOrd::gt(self.as_str(), &rhs[..])
}
#[inline]
fn ge(&self, rhs: &$rhs) -> bool {
PartialOrd::ge(self.as_str(), &rhs[..])
}
}
};
}
impl_eq_ord! {NamespaceComponent<'_>, str}
impl_eq_ord! {NamespaceComponent<'_>, &str}
impl_eq_ord! {NamespaceComponent<'_>, &mut str}
#[cfg(any(feature = "alloc", test))]
impl_eq_ord! {NamespaceComponent<'_>, alloc::string::String}
#[cfg(any(feature = "alloc", test))]
impl_eq_ord! {NamespaceComponent<'_>, alloc::borrow::Cow<'_, str>}
#[cfg(any(feature = "std", test))]
macro_rules! impl_eq_ord_osstr {
{$lhs:ty, $rhs:ty $(, $rhs_extract:expr)?} => {
impl PartialEq<$rhs> for $lhs {
#[inline]
fn eq(&self, rhs: &$rhs) -> bool {
PartialEq::eq(self.as_os_str(), impl_eq_ord_osstr!(@rhs_extract $({closure: $rhs_extract})? {rhs: rhs}))
}
#[allow(clippy::partialeq_ne_impl)]
#[inline]
fn ne(&self, rhs: &$rhs) -> bool {
PartialEq::ne(self.as_os_str(), impl_eq_ord_osstr!(@rhs_extract $({closure: $rhs_extract})? {rhs: rhs}))
}
}
impl PartialOrd<$rhs> for $lhs {
#[inline]
fn partial_cmp(&self, rhs: &$rhs) -> Option<core::cmp::Ordering> {
PartialOrd::partial_cmp(self.as_os_str(), impl_eq_ord_osstr!(@rhs_extract $({closure: $rhs_extract})? {rhs: rhs}))
}
#[inline]
fn lt(&self, rhs: &$rhs) -> bool {
PartialOrd::lt(self.as_os_str(), impl_eq_ord_osstr!(@rhs_extract $({closure: $rhs_extract})? {rhs: rhs}))
}
#[inline]
fn le(&self, rhs: &$rhs) -> bool {
PartialOrd::le(self.as_os_str(), impl_eq_ord_osstr!(@rhs_extract $({closure: $rhs_extract})? {rhs: rhs}))
}
#[inline]
fn gt(&self, rhs: &$rhs) -> bool {
PartialOrd::gt(self.as_os_str(), impl_eq_ord_osstr!(@rhs_extract $({closure: $rhs_extract})? {rhs: rhs}))
}
#[inline]
fn ge(&self, rhs: &$rhs) -> bool {
PartialOrd::ge(self.as_os_str(), impl_eq_ord_osstr!(@rhs_extract $({closure: $rhs_extract})? {rhs: rhs}))
}
}
};
{@rhs_extract {closure: $closure:expr} {rhs: $rhs_expr:expr}} => {
($closure)($rhs_expr)
};
{@rhs_extract {rhs: $rhs_expr:expr}} => {
AsRef::<std::ffi::OsStr>::as_ref($rhs_expr)
};
}
#[cfg(any(feature = "std", test))]
impl_eq_ord_osstr! {NamespaceComponent<'_>, std::ffi::OsStr}
#[cfg(any(feature = "std", test))]
impl_eq_ord_osstr! {NamespaceComponent<'_>, std::path::Path}
#[cfg(any(feature = "std", test))]
impl_eq_ord_osstr! {NamespaceComponent<'_>, &std::ffi::OsStr}
#[cfg(any(feature = "std", test))]
impl_eq_ord_osstr! {NamespaceComponent<'_>, &std::path::Path}
#[cfg(any(feature = "std", test))]
impl_eq_ord_osstr! {NamespaceComponent<'_>, &mut std::ffi::OsStr}
#[cfg(any(feature = "std", test))]
impl_eq_ord_osstr! {NamespaceComponent<'_>, &mut std::path::Path}
#[cfg(any(feature = "std", test))]
impl_eq_ord_osstr! {NamespaceComponent<'_>, std::ffi::OsString}
#[cfg(any(feature = "std", test))]
impl_eq_ord_osstr! {NamespaceComponent<'_>, std::path::PathBuf}
#[cfg(any(feature = "std", test))]
impl_eq_ord_osstr! {NamespaceComponent<'_>, alloc::borrow::Cow<'_, std::ffi::OsStr>}
#[cfg(any(feature = "std", test))]
impl_eq_ord_osstr! {NamespaceComponent<'_>, alloc::borrow::Cow<'_, std::path::Path>, cow_path_as_osstr}
#[cfg(any(feature = "std", test))]
#[inline]
fn cow_path_as_osstr<'u>(v: &'u alloc::borrow::Cow<'u, std::path::Path>) -> &'u std::ffi::OsStr {
v.as_os_str()
}
#[cfg(test)]
mod test_get_components {
use crate::component::NamespaceComponent;
use super::get_components;
#[test]
pub fn get_components_test() {
fn get_components_collect(v: &str) -> Vec<NamespaceComponent<'_>> {
get_components(v).collect()
}
assert_eq!(get_components_collect("::a::b"), vec!["a", "b"]);
assert_eq!(get_components_collect("a::b::c::"), vec!["a", "b", "c", ""]);
assert_eq!(get_components_collect("::"), vec![""]);
assert_eq!(get_components_collect("africa::tunisia"), vec![
"africa", "tunisia"
]);
assert_eq!(get_components_collect("::africa::tunisia"), vec![
"africa", "tunisia"
]);
}
}