Skip to main content

flashkraft_core/utils/
logger.rs

1//! Debug Logging Utilities
2//!
3//! Centralized logging macros and utilities for FlashKraft.
4//! All debug logging is conditionally compiled and only active in debug builds.
5
6/// Internal implementation for debug-only tagged logging.
7///
8/// Not intended for direct use — call [`debug_log!`], [`flash_debug!`], or
9/// [`status_log!`] instead.
10#[doc(hidden)]
11#[macro_export]
12macro_rules! __debug_log_impl {
13    ($tag:expr, $($arg:tt)*) => {
14        #[cfg(debug_assertions)]
15        eprintln!(concat!("[", $tag, "] {}"), format!($($arg)*));
16    };
17}
18
19/// Debug logging macro for general application messages.
20///
21/// Only prints in debug builds. Automatically prefixes with `[DEBUG]`.
22/// Delegates to [`__debug_log_impl!`].
23///
24/// # Example
25/// ```no_run
26/// # use flashkraft_core::debug_log;
27/// let path = "/path/to/image.iso";
28/// debug_log!("User selected image: {}", path);
29/// ```
30#[macro_export]
31macro_rules! debug_log {
32    ($($arg:tt)*) => { $crate::__debug_log_impl!("DEBUG", $($arg)*) };
33}
34
35/// Debug logging macro for flash subscription messages.
36///
37/// Only prints in debug builds. Automatically prefixes with `[FLASH_DEBUG]`.
38/// Delegates to [`__debug_log_impl!`].
39///
40/// # Example
41/// ```no_run
42/// # use flashkraft_core::flash_debug;
43/// let progress = 0.75;
44/// flash_debug!("Progress: {:.1}%", progress * 100.0);
45/// ```
46#[macro_export]
47macro_rules! flash_debug {
48    ($($arg:tt)*) => { $crate::__debug_log_impl!("FLASH_DEBUG", $($arg)*) };
49}
50
51/// Debug logging macro for status messages.
52///
53/// Only prints in debug builds. Automatically prefixes with `[STATUS]`.
54/// Delegates to [`__debug_log_impl!`].
55///
56/// # Example
57/// ```no_run
58/// # use flashkraft_core::status_log;
59/// status_log!("Starting flash operation");
60/// ```
61#[macro_export]
62macro_rules! status_log {
63    ($($arg:tt)*) => { $crate::__debug_log_impl!("STATUS", $($arg)*) };
64}
65
66/// Conditional debug logging - only logs if condition is true
67///
68/// # Example
69/// ```no_run
70/// # use flashkraft_core::debug_if;
71/// let verbose_mode = true;
72/// let data = vec![1, 2, 3];
73/// debug_if!(verbose_mode, "Detailed info: {:?}", data);
74/// ```
75#[macro_export]
76macro_rules! debug_if {
77    ($condition:expr, $($arg:tt)*) => {
78        #[cfg(debug_assertions)]
79        if $condition {
80            eprintln!("[DEBUG] {}", format!($($arg)*));
81        }
82    };
83}
84
85/// Format a byte count as a compact human-readable string.
86///
87/// Uses binary prefixes (1 KiB = 1024 bytes) and one decimal place.
88/// Output examples: `"1.5G"`, `"512.0M"`, `"3.2K"`, `"42B"`.
89///
90/// # Example
91/// ```
92/// use flashkraft_core::fmt_bytes;
93/// assert_eq!(fmt_bytes(0),              "0B");
94/// assert_eq!(fmt_bytes(1_023),          "1023B");
95/// assert_eq!(fmt_bytes(1_024),          "1.0K");
96/// assert_eq!(fmt_bytes(1_048_576),      "1.0M");
97/// assert_eq!(fmt_bytes(1_073_741_824),  "1.0G");
98/// ```
99pub fn fmt_bytes(bytes: u64) -> String {
100    const GIB: u64 = 1_073_741_824;
101    const MIB: u64 = 1_048_576;
102    const KIB: u64 = 1_024;
103
104    if bytes >= GIB {
105        format!("{:.1}G", bytes as f64 / GIB as f64)
106    } else if bytes >= MIB {
107        format!("{:.1}M", bytes as f64 / MIB as f64)
108    } else if bytes >= KIB {
109        format!("{:.1}K", bytes as f64 / KIB as f64)
110    } else {
111        format!("{bytes}B")
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    #[test]
118    fn test_debug_macros_compile() {
119        // These should compile without errors
120        debug_log!("Test message");
121        flash_debug!("Flash test: {}", 42);
122        status_log!("Status test");
123        debug_if!(true, "Conditional test");
124    }
125
126    // ── fmt_bytes ─────────────────────────────────────────────────────────────
127
128    #[test]
129    fn fmt_bytes_zero() {
130        assert_eq!(super::fmt_bytes(0), "0B");
131    }
132
133    #[test]
134    fn fmt_bytes_bytes_range() {
135        assert_eq!(super::fmt_bytes(1), "1B");
136        assert_eq!(super::fmt_bytes(1_023), "1023B");
137    }
138
139    #[test]
140    fn fmt_bytes_kib_boundary() {
141        assert_eq!(super::fmt_bytes(1_024), "1.0K");
142        assert_eq!(super::fmt_bytes(1_536), "1.5K");
143        assert_eq!(super::fmt_bytes(1_047_552), "1023.0K");
144    }
145
146    #[test]
147    fn fmt_bytes_mib_boundary() {
148        assert_eq!(super::fmt_bytes(1_048_576), "1.0M");
149        assert_eq!(super::fmt_bytes(524_288_000), "500.0M");
150    }
151
152    #[test]
153    fn fmt_bytes_gib_boundary() {
154        assert_eq!(super::fmt_bytes(1_073_741_824), "1.0G");
155        assert_eq!(super::fmt_bytes(32_212_254_720), "30.0G");
156    }
157}