use core::fmt;
use super::{NamespacePath, RawNamespacePath};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
pub struct MaybeWithPrefix<Component> {
pub render_prefix: bool,
pub component: Component,
}
impl<Component> MaybeWithPrefix<Component> {
#[inline]
pub const fn new(render_prefix: bool, component: Component) -> Self {
Self {
render_prefix,
component,
}
}
#[inline]
const fn wrap_single_element(render_style: RenderStyle, component: Component) -> Self {
match render_style {
RenderStyle::WithFirstSeparator => Self::new(true, component),
RenderStyle::NoFirstSeparator => Self::new(false, component),
}
}
}
impl<Component: fmt::Display> fmt::Display for MaybeWithPrefix<Component> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.render_prefix {
f.write_str("::")?;
}
self.component.fmt(f)
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Default)]
pub struct DisplayPrefixIter<Iter> {
remaining_element_format: RenderStyle,
inner: Iter,
}
impl<Iter> DisplayPrefixIter<Iter> {
#[inline]
pub const fn new(components: Iter, render_style: RenderStyle) -> Self {
Self {
remaining_element_format: render_style,
inner: components,
}
}
}
impl<Iter: Iterator> Iterator for DisplayPrefixIter<Iter> {
type Item = MaybeWithPrefix<Iter::Item>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let next_v = self
.inner
.next()
.map(|i| MaybeWithPrefix::wrap_single_element(self.remaining_element_format, i));
self.remaining_element_format = RenderStyle::WithFirstSeparator;
next_v
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum RenderStyle {
#[default]
WithFirstSeparator,
NoFirstSeparator,
}
impl RenderStyle {
#[must_use]
#[inline]
pub const fn separator_count(&self, components: usize) -> usize {
match self {
RenderStyle::WithFirstSeparator => components,
RenderStyle::NoFirstSeparator => components.saturating_sub(1),
}
}
}
#[cfg(test)]
mod test_render_prefix_components {
use core::fmt;
use crate::path::render::DisplayPrefixIter;
#[test]
fn prefix_emit_components_test() {
use super::RenderStyle::{self, NoFirstSeparator, WithFirstSeparator};
struct RenderIterator<I>(pub I);
impl<I: Iterator<Item: fmt::Display> + Clone> fmt::Display for RenderIterator<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.clone().try_fold((), |_, v| v.fmt(f))
}
}
fn render_in_style(
components: impl IntoIterator<Item: fmt::Display, IntoIter: Clone>,
style: RenderStyle,
) -> String {
RenderIterator(DisplayPrefixIter::new(components.into_iter(), style)).to_string()
}
assert_eq!(render_in_style([""], WithFirstSeparator), "::");
assert_eq!(render_in_style([""], NoFirstSeparator), "");
assert_eq!(render_in_style(["a"], WithFirstSeparator), "::a");
assert_eq!(render_in_style(["a"], NoFirstSeparator), "a");
assert_eq!(render_in_style(["a", "b"], WithFirstSeparator), "::a::b");
assert_eq!(render_in_style(["a", "b"], NoFirstSeparator), "a::b");
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
pub struct NamespacePathRender<NSPath>(pub NSPath, pub RenderStyle);
impl<NSPath> NamespacePathRender<NSPath> {
#[inline]
#[must_use]
pub const fn new(namespace_path: NSPath, render_style: RenderStyle) -> Self {
Self(namespace_path, render_style)
}
#[inline]
#[must_use]
pub const fn with_first_separator(namespace_path: NSPath) -> Self {
Self::new(namespace_path, RenderStyle::WithFirstSeparator)
}
#[inline]
#[must_use]
pub const fn without_first_separator(namespace_path: NSPath) -> Self {
Self::new(namespace_path, RenderStyle::NoFirstSeparator)
}
#[inline]
#[must_use]
pub fn estimated_string_bytes(&self) -> usize
where
NSPath: NamespacePath,
{
self.0.components_hint().estimated_string_bytes(self.1)
}
#[allow(
clippy::inherent_to_string_shadow_display,
reason = "this just calls out to the fmt::Display impl directly but adds better pre-allocation"
)]
#[must_use]
#[cfg(any(feature = "alloc", test))]
pub fn to_string(&self) -> alloc::string::String
where
NSPath: NamespacePath,
{
use fmt::Write;
let estimated_bytes = self.estimated_string_bytes();
let mut v = alloc::string::String::with_capacity(estimated_bytes);
write!(v, "{self}").expect("in-memory writing, should not have error");
v
}
}
impl<NSPath: NamespacePath> fmt::Display for NamespacePathRender<NSPath> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
DisplayPrefixIter::new(self.0.components().into_iter(), self.1)
.try_fold((), |_, v| v.fmt(f))
}
}
impl<Inner: NamespacePath> NamespacePath for NamespacePathRender<Inner> {
#[inline]
fn components(&self) -> impl IntoIterator<Item = crate::NamespaceComponent<'_>> {
self.0.components()
}
#[inline]
fn components_hint(&self) -> super::NamespaceComponentsHint {
self.0.components_hint()
}
}
impl<Inner: RawNamespacePath> RawNamespacePath for NamespacePathRender<Inner> {
#[inline]
fn raw_components(&self) -> impl IntoIterator<Item = impl fmt::Display> {
self.0.raw_components()
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
pub struct RawNamespacePathRender<RawNSPath>(pub RawNSPath, pub RenderStyle);
impl<RawNSPath> RawNamespacePathRender<RawNSPath> {
#[inline]
#[must_use]
pub const fn new(raw_namespace_path: RawNSPath, render_style: RenderStyle) -> Self {
Self(raw_namespace_path, render_style)
}
#[inline]
#[must_use]
pub const fn with_first_separator(raw_namespace_path: RawNSPath) -> Self {
Self::new(raw_namespace_path, RenderStyle::WithFirstSeparator)
}
#[inline]
#[must_use]
pub const fn without_first_separator(raw_namespace_path: RawNSPath) -> Self {
Self::new(raw_namespace_path, RenderStyle::NoFirstSeparator)
}
}
impl<RawNSPath: RawNamespacePath> fmt::Display for RawNamespacePathRender<RawNSPath> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
DisplayPrefixIter::new(self.0.raw_components().into_iter(), self.1)
.try_fold((), |_, v| v.fmt(f))
}
}
impl<Inner: NamespacePath> NamespacePath for RawNamespacePathRender<Inner> {
#[inline]
fn components(&self) -> impl IntoIterator<Item = crate::NamespaceComponent<'_>> {
self.0.components()
}
#[inline]
fn components_hint(&self) -> super::NamespaceComponentsHint {
self.0.components_hint()
}
}
impl<Inner: RawNamespacePath> RawNamespacePath for RawNamespacePathRender<Inner> {
#[inline]
fn raw_components(&self) -> impl IntoIterator<Item = impl fmt::Display> {
self.0.raw_components()
}
}