jj-analyze 0.5.0

Analyze a revset and display a tree showing how it will be evaluated
use std::borrow::Cow;
use std::fmt;
use std::ops::Range;

use crate::print::format_range;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum AnalyzeCost {
    Fast,
    Slow,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, clap::ValueEnum)]
pub enum AnalyzeContext {
    Eager,
    Lazy,
    Predicate,
    #[value(skip)]
    Resolved,
}

impl AnalyzeContext {
    pub fn predicate_to_lazy(self) -> Self {
        match self {
            Self::Predicate => Self::Lazy,
            other => other,
        }
    }

    pub fn eager_to_lazy(self) -> Self {
        match self {
            Self::Eager => Self::Lazy,
            other => other,
        }
    }
}

impl fmt::Display for AnalyzeContext {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Eager => write!(f, "eager"),
            Self::Lazy => write!(f, "lazy"),
            Self::Predicate => write!(f, "predicate"),
            Self::Resolved => write!(f, "resolved"),
        }
    }
}

#[derive(Debug)]
pub struct TreeEntry<'a> {
    pub name: Cow<'a, str>,
    pub context: AnalyzeContext,
    pub children: Vec<Child<'a>>,
}

#[derive(Debug)]
pub struct Child<'a> {
    pub label: Option<Cow<'a, str>>,
    pub context: AnalyzeContext,
    pub tree: &'a dyn AnalyzeTree,
}

pub trait AnalyzeTree: fmt::Debug {
    fn entry(&self, context: AnalyzeContext) -> TreeEntry<'_>;
    fn cost(&self, context: AnalyzeContext) -> AnalyzeCost;
}

impl AnalyzeTree for usize {
    fn entry(&self, _context: AnalyzeContext) -> TreeEntry<'_> {
        TreeEntry {
            name: self.to_string().into(),
            context: AnalyzeContext::Resolved,
            children: vec![],
        }
    }

    fn cost(&self, _context: AnalyzeContext) -> AnalyzeCost {
        AnalyzeCost::Fast
    }
}

impl AnalyzeTree for Range<u64> {
    fn entry(&self, _context: AnalyzeContext) -> TreeEntry<'_> {
        TreeEntry {
            name: format_range(self, 0..u64::MAX).into(),
            context: AnalyzeContext::Resolved,
            children: vec![],
        }
    }

    fn cost(&self, _context: AnalyzeContext) -> AnalyzeCost {
        AnalyzeCost::Fast
    }
}

impl AnalyzeTree for Range<u32> {
    fn entry(&self, _context: AnalyzeContext) -> TreeEntry<'_> {
        TreeEntry {
            name: format_range(self, 0..u32::MAX).into(),
            context: AnalyzeContext::Resolved,
            children: vec![],
        }
    }

    fn cost(&self, _context: AnalyzeContext) -> AnalyzeCost {
        AnalyzeCost::Fast
    }
}