1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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);

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);
        }
    }
}

/// 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)
    }};
}