Skip to main content

dear_imgui_rs/utils/
logging.rs

1use crate::sys;
2
3/// Auto-open depth for Dear ImGui logging helpers.
4///
5/// Dear ImGui uses `-1` to mean "use the configured default depth". This type keeps that sentinel
6/// out of the safe Rust API while still allowing an explicit non-negative tree depth.
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub struct LogAutoOpenDepth(Option<u32>);
9
10impl LogAutoOpenDepth {
11    /// Use Dear ImGui's configured default log auto-open depth.
12    pub const DEFAULT: Self = Self(None);
13
14    /// Create an explicit non-negative auto-open depth.
15    ///
16    /// Panics if `depth` exceeds Dear ImGui's signed `int` range.
17    #[inline]
18    pub const fn new(depth: u32) -> Self {
19        assert!(
20            depth <= i32::MAX as u32,
21            "LogAutoOpenDepth::new() depth exceeded i32::MAX"
22        );
23        Self(Some(depth))
24    }
25
26    #[inline]
27    pub(crate) const fn raw(self) -> i32 {
28        match self.0 {
29            Some(depth) => depth as i32,
30            None => -1,
31        }
32    }
33}
34
35impl From<u32> for LogAutoOpenDepth {
36    fn from(depth: u32) -> Self {
37        Self::new(depth)
38    }
39}
40
41impl crate::ui::Ui {
42    /// Start logging to TTY.
43    #[doc(alias = "LogToTTY")]
44    pub fn log_to_tty(&self, auto_open_depth: impl Into<LogAutoOpenDepth>) {
45        unsafe { sys::igLogToTTY(auto_open_depth.into().raw()) }
46    }
47
48    /// Start logging to file with the default filename.
49    #[doc(alias = "LogToFile")]
50    pub fn log_to_file_default(&self, auto_open_depth: impl Into<LogAutoOpenDepth>) {
51        unsafe { sys::igLogToFile(auto_open_depth.into().raw(), std::ptr::null()) }
52    }
53
54    /// Start logging to file.
55    ///
56    /// # Errors
57    ///
58    /// Returns an error if `filename` contains NUL bytes.
59    #[doc(alias = "LogToFile")]
60    pub fn log_to_file(
61        &self,
62        auto_open_depth: impl Into<LogAutoOpenDepth>,
63        filename: &std::path::Path,
64    ) -> crate::error::ImGuiResult<()> {
65        use crate::error::SafeStringConversion;
66        let cstr = filename.to_string_lossy().into_owned().to_cstring_safe()?;
67        unsafe { sys::igLogToFile(auto_open_depth.into().raw(), cstr.as_ptr()) }
68        Ok(())
69    }
70
71    /// Start logging to clipboard.
72    #[doc(alias = "LogToClipboard")]
73    pub fn log_to_clipboard(&self, auto_open_depth: impl Into<LogAutoOpenDepth>) {
74        unsafe { sys::igLogToClipboard(auto_open_depth.into().raw()) }
75    }
76
77    /// Show ImGui's logging buttons (TTY/File/Clipboard).
78    #[doc(alias = "LogButtons")]
79    pub fn log_buttons(&self) {
80        unsafe { sys::igLogButtons() }
81    }
82
83    /// Finish logging (close file / copy to clipboard as needed).
84    #[doc(alias = "LogFinish")]
85    pub fn log_finish(&self) {
86        unsafe { sys::igLogFinish() }
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    #[test]
93    fn log_auto_open_depth_preserves_default_sentinel_and_rejects_overflow() {
94        assert_eq!(super::LogAutoOpenDepth::DEFAULT.raw(), -1);
95        assert_eq!(super::LogAutoOpenDepth::new(0).raw(), 0);
96        assert_eq!(super::LogAutoOpenDepth::new(3).raw(), 3);
97        assert!(
98            std::panic::catch_unwind(|| super::LogAutoOpenDepth::new(i32::MAX as u32 + 1)).is_err()
99        );
100    }
101}