kerf 0.1.2

Simple tokio-based trace event collector
Documentation
use serde::{Deserialize, Serialize};

use crate::{IntoMatcherSet, Match, MatcherSet, StatsConfig};

// Main config structure
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
    pub tabs: Vec<Tab>,
    pub stats_config: Option<StatsConfig>,
}

impl Default for Config {
    fn default() -> Self {
        Self::default_main()
    }
}

impl Config {
    pub fn empty() -> Self {
        Self {
            tabs: vec![],
            stats_config: None,
        }
    }

    pub fn default_main() -> Self {
        Self {
            tabs: vec![Tab::default()],
            stats_config: None,
        }
    }

    pub fn from_tab(tab: impl Into<Tab>) -> Self {
        Self {
            tabs: vec![tab.into()],
            stats_config: None,
        }
    }

    // Updated to use the builder pattern for better type inference
    pub fn from_tabs<I>(tabs: I) -> Self
    where
        I: IntoIterator,
        I::Item: IntoTracerTab,
    {
        Self {
            tabs: tabs
                .into_iter()
                .map(|item| item.into_tracer_tab())
                .collect(),
            stats_config: None,
        }
    }

    /// Add a single tab to the config and return the modified config
    pub fn main_tab(self, matcher_set: impl IntoMatcherSet) -> Self {
        self.with_tab("Main", matcher_set)
    }

    /// Add a single tab to the config and return the modified config
    pub fn with_tab(mut self, name: impl Into<String>, matcher_set: impl IntoMatcherSet) -> Self {
        self.tabs
            .push(Tab::new(name.into()).with_matcher_set(matcher_set.into_matcher_set()));
        self
    }

    /// Add multiple tabs to the config and return the modified config
    pub fn with_tabs(
        mut self,
        tabs: impl IntoIterator<Item = (impl Into<String>, impl IntoMatcherSet)>,
    ) -> Self {
        for (name, matcher_set) in tabs {
            self.tabs
                .push(Tab::new(name.into()).with_matcher_set(matcher_set.into_matcher_set()));
        }
        self
    }

    /// Enable stats tracking
    pub fn with_stats(mut self, config: StatsConfig) -> Self {
        self.stats_config = Some(config);
        self
    }

    /// Add a single tab to the config in-place
    pub fn add_tab(&mut self, name: impl Into<String>, matcher_set: impl IntoMatcherSet) {
        self.tabs
            .push(Tab::new(name.into()).with_matcher_set(matcher_set.into_matcher_set()));
    }

    /// Add multiple tabs to the config in-place
    pub fn add_tabs(
        &mut self,
        tabs: impl IntoIterator<Item = (impl Into<String>, impl IntoMatcherSet)>,
    ) {
        for (name, matcher_set) in tabs {
            self.tabs
                .push(Tab::new(name.into()).with_matcher_set(matcher_set.into_matcher_set()));
        }
    }
}

// Configuration struct for tabs
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Tab {
    pub name: String,
    pub matcher_set: MatcherSet,
}

impl Default for Tab {
    fn default() -> Self {
        Self {
            name: "Main".to_string(),
            matcher_set: MatcherSet::from_matcher(Match::debug().all_modules()),
        }
    }
}

// Trait for converting things into TracerTab
pub trait IntoTracerTab {
    fn into_tracer_tab(self) -> Tab;
}

// TracerTab already is a TracerTab
impl IntoTracerTab for Tab {
    fn into_tracer_tab(self) -> Tab {
        self
    }
}

// Tuple implementations that work with any IntoMatcherSet
impl<S, M> IntoTracerTab for (S, M)
where
    S: Into<String>,
    M: IntoMatcherSet,
{
    fn into_tracer_tab(self) -> Tab {
        Tab {
            name: self.0.into(),
            matcher_set: self.1.into_matcher_set(),
        }
    }
}

// Keep the From implementations for backward compatibility
impl<S> From<(S, MatcherSet)> for Tab
where
    S: Into<String>,
{
    fn from((name, matcher_set): (S, MatcherSet)) -> Self {
        Self {
            name: name.into(),
            matcher_set,
        }
    }
}

impl<S> From<(S, Match)> for Tab
where
    S: Into<String>,
{
    fn from((name, matcher): (S, Match)) -> Self {
        Self {
            name: name.into(),
            matcher_set: MatcherSet::from_matcher(matcher),
        }
    }
}

impl Tab {
    pub fn new(name: String) -> Self {
        Self {
            name,
            matcher_set: MatcherSet::empty(),
        }
    }

    pub fn with_matcher_set(mut self, matcher_set: MatcherSet) -> Self {
        self.matcher_set = matcher_set;
        self
    }

    pub fn add_matcher(mut self, matcher: Match) -> Self {
        self.matcher_set.add_matcher(matcher);
        self
    }
}

// Helper function for creating tabs when you need more flexibility
impl Tab {
    pub fn from_name_and_matchers<S, M>(name: S, matchers: M) -> Self
    where
        S: Into<String>,
        M: IntoMatcherSet,
    {
        Self {
            name: name.into(),
            matcher_set: matchers.into_matcher_set(),
        }
    }
}