tracy-client 0.18.0

High level bindings to the client libraries for the Tracy profiler
Documentation
use crate::Client;

/// Name of a plot.
///
/// Create with the [`plot_name!`](crate::plot_name) macro.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct PlotName(pub(crate) &'static str);

/// The format of a plot to be shown in the Tracy profiler UI.
#[derive(Debug, Hash, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
#[non_exhaustive]
pub enum PlotFormat {
    /// Values will be displayed as plain numbers. This is the default.
    #[default]
    Number,

    /// Values will be displayed as byte counts, showing as kilobytes, megabytes, etc.
    Memory,

    /// Values will be shown as a percentage (with 100 being equal to 100%).
    Percentage,

    /// Values will be shown as watts.
    Watts,
}

/// The style of lines of a plot, shown in the Tracy profiler UI.
#[derive(Debug, Hash, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
#[non_exhaustive]
pub enum PlotLineStyle {
    /// Lines will be stepped (ie look like a staircase).
    Stepped,

    /// Lines will be smooth (interpolating a line between two values).
    #[default]
    Smooth,
}

/// Configuration for how a plot appears in the Tracy profiling UI.
///
/// # Examples
///
/// ```
/// # use tracy_client::PlotConfiguration;
/// // Create a red plot line.
/// let configuration = PlotConfiguration::default().fill(false).color(Some(0xFF0000));
/// ```
#[derive(Clone, PartialEq, Debug)]
pub struct PlotConfiguration {
    /// The format of values on the plot.
    format: PlotFormat,

    /// The style of lines on the plot.
    line_style: PlotLineStyle,

    /// Whether the plot should be filled with a solid color below the line.
    fill: bool,

    /// A custom color of this plot. None means a default color will be generated by Tracy.
    color: Option<u32>,
}

impl PlotConfiguration {
    /// Sets the format of values on the plot.
    pub fn format(mut self, format: PlotFormat) -> Self {
        self.format = format;
        self
    }

    /// Sets the style of lines on the plot.
    pub fn line_style(mut self, line_style: PlotLineStyle) -> Self {
        self.line_style = line_style;
        self
    }

    /// Sets whether the plot should be filled with a solid color below the line.
    pub fn fill(mut self, fill: bool) -> Self {
        self.fill = fill;
        self
    }

    /// Sets a custom color of the plot. A value of `None` will cause Tracy to create its own color.
    ///
    /// # Examples
    ///
    /// ```
    /// # use tracy_client::PlotConfiguration;
    /// // Configure the plot to be red.
    /// let red = PlotConfiguration::default().color(Some(0xFF0000));
    /// // Configure the plot to be green.
    /// let green = PlotConfiguration::default().color(Some(0x00FF00));
    /// // Configure the plot to be blue.
    /// let blue = PlotConfiguration::default().color(Some(0x0000FF));
    /// ```
    pub fn color(mut self, color: Option<u32>) -> Self {
        self.color = color;
        self
    }
}

impl Default for PlotConfiguration {
    fn default() -> Self {
        Self {
            format: Default::default(),
            line_style: Default::default(),
            fill: true,
            color: None,
        }
    }
}

impl PlotName {
    /// Construct a `PlotName` dynamically, leaking the provided String.
    ///
    /// You should call this function once for a given name, and store the returned `PlotName` for
    /// continued use, to avoid rapid memory use growth. Whenever possible, prefer the
    /// [`plot_name!`](crate::plot_name) macro, which takes a literal name and doesn't leak memory.
    ///
    /// The resulting value may be used as an argument for the the [`Client::secondary_frame_mark`]
    /// and [`Client::non_continuous_frame`] methods.
    #[must_use]
    pub fn new_leak(name: String) -> Self {
        #[cfg(feature = "enable")]
        {
            // Ensure the name is null-terminated.
            let mut name = name;
            name.push('\0');
            // Drop excess capacity by converting into a boxed str, then leak.
            let name = Box::leak(name.into_boxed_str());
            Self(name)
        }
        #[cfg(not(feature = "enable"))]
        {
            drop(name);
            Self("\0")
        }
    }
}

/// Instrumentation for drawing 2D plots.
impl Client {
    /// Add a point with an y-axis value of `value` to the plot named `plot_name`.
    ///
    /// # Examples
    ///
    /// ```
    /// # let client = tracy_client::Client::start();
    /// tracy_client::Client::running()
    ///     .expect("client must be running")
    ///     .plot(tracy_client::plot_name!("temperature"), 37.0);
    /// ```
    pub fn plot(&self, plot_name: PlotName, value: f64) {
        #[cfg(feature = "enable")]
        unsafe {
            // SAFE: We made sure the `plot` refers to a null-terminated string.
            let () = sys::___tracy_emit_plot(plot_name.0.as_ptr().cast(), value);
        }
    }

    /// Sets the display configuration of the plot named `plot_name`.
    ///
    /// # Examples
    ///
    /// ```
    /// use tracy_client::{PlotConfiguration, PlotFormat};
    /// # let client = tracy_client::Client::start();
    /// tracy_client::Client::running()
    ///     .expect("client must be running")
    ///     .plot_config(tracy_client::plot_name!("memory"), PlotConfiguration::default().format(PlotFormat::Memory));
    /// ```
    pub fn plot_config(&self, plot_name: PlotName, configuration: PlotConfiguration) {
        #[cfg(feature = "enable")]
        {
            let format = match configuration.format {
                PlotFormat::Number => sys::TracyPlotFormatEnum_TracyPlotFormatNumber,
                PlotFormat::Memory => sys::TracyPlotFormatEnum_TracyPlotFormatMemory,
                PlotFormat::Percentage => sys::TracyPlotFormatEnum_TracyPlotFormatPercentage,
                PlotFormat::Watts => sys::TracyPlotFormatEnum_TracyPlotFormatWatt,
            } as std::os::raw::c_int;
            let stepped = configuration.line_style == PlotLineStyle::Stepped;
            let filled = configuration.fill;
            let color = configuration.color.unwrap_or(0);
            unsafe {
                // SAFE: We made sure the `plot` refers to a null-terminated string.
                let () = sys::___tracy_emit_plot_config(
                    plot_name.0.as_ptr().cast(),
                    format,
                    stepped.into(),
                    filled.into(),
                    color,
                );
            }
        }
    }
}

/// Construct a [`PlotName`].
///
/// The resulting value may be used as an argument for the [`Client::plot`] method. The macro can
/// be used in a `const` context.
#[macro_export]
macro_rules! plot_name {
    ($name: expr) => {
        unsafe { $crate::internal::create_plot(concat!($name, "\0")) }
    };
}

/// Convenience macro for [`Client::plot`] on the current client.
///
/// # Panics
///
/// - If a `Client` isn't currently running.
#[macro_export]
macro_rules! plot {
    ($name: expr, $value: expr) => {{
        $crate::Client::running()
            .expect("plot! without a running Client")
            .plot($crate::plot_name!($name), $value)
    }};
}