cargo-whatfeatures 0.9.13

display features, versions and dependencies of crates
Documentation
use std::{
    borrow::Cow,
    fmt::Display,
    io::{self, Write},
};

use super::{Style, Theme};

pub trait Item: Clone {
    type Child: Item;
    fn write<W: Write + ?Sized>(&self, writer: &mut W) -> io::Result<()>;
    fn children(&self) -> Cow<[Self::Child]>;
}

#[derive(Debug, Clone)]
pub struct Node {
    pub text: String,
    pub children: Vec<Self>,
}

impl Node {
    pub fn new<S, I>(data: S, children: I) -> Self
    where
        S: ToString,
        I: IntoIterator,
        I::Item: Into<Self>,
    {
        Self {
            text: data.to_string(),
            children: children.into_iter().map(Into::into).collect(),
        }
    }

    pub fn add_child(&mut self, child: impl Into<Self>) {
        self.children.push(child.into());
    }

    pub fn empty<S: ToString>(data: S) -> Self {
        Self {
            text: data.to_string(),
            children: vec![],
        }
    }
}

impl Item for Node {
    type Child = Self;

    fn write<W: Write + ?Sized>(&self, writer: &mut W) -> io::Result<()> {
        write!(writer, "{}", self.text)
    }

    fn children(&self) -> Cow<[Self::Child]> {
        self.children[..].into()
    }
}

impl<T: ToString> From<T> for Node {
    fn from(data: T) -> Self {
        Self {
            text: data.to_string(),
            children: Vec::new(),
        }
    }
}

pub trait Printer {
    fn print<W: Write + ?Sized>(self, writer: &mut W, theme: &Theme) -> io::Result<()>;
}

impl<T: Item> Printer for T {
    fn print<W: Write + ?Sized>(self, writer: &mut W, theme: &Theme) -> io::Result<()> {
        print(self, writer, theme)
    }
}

pub fn print(item: impl Item, writer: &mut (impl Write + ?Sized), theme: &Theme) -> io::Result<()> {
    Appearance {
        style: &Style::default(),
        theme,
    }
    .print(&item, writer, "", "", 0)
}

struct Appearance<'a, 'b> {
    theme: &'a Theme,
    style: &'b Style,
}

impl<'a, 'b> Appearance<'a, 'b> {
    fn print(
        &self,
        item: &impl Item,
        writer: &mut (impl Write + ?Sized),
        left: impl Display,
        child: impl Display,
        depth: usize,
    ) -> std::io::Result<()> {
        let Appearance { style, theme } = self;

        write!(writer, "{}", theme.tree.paint(left))?;
        item.write(writer)?;
        writeln!(writer)?;

        if let Some((last, children)) = item.children().split_last() {
            let left_prefix = format!("{}{}", child, style.branch);
            let right_prefix = format!("{}{}", child, style.pipe);

            for child in children {
                self.print(child, writer, &left_prefix, &right_prefix, depth + 1)?;
            }

            self.print(
                last,
                writer,
                format!("{}{}", child, style.edge),
                format!("{}{}", child, style.last),
                depth + 1,
            )?;
        }

        Ok(())
    }
}