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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
//! Macros for logging and debug assertions. [`nih_dbg!()`], [`nih_trace!()`], and the
//! `nih_debug_assert_*!()` macros are compiled out during release builds, so they can be used for
//! asserting adiditonal invariants in debug builds. Check the [`nih_log!()`] macro for more
//! information on NIH-plug's logger. None of the logging functions are realtime-safe, and you
//! should avoid using them during release builds in any of the functions that may be called from an
//! audio thread.

// NOTE: Exporting macros in Rust is a bit weird. `#[macro_export]` causes them to be exported to
//       the crate root, but that makes it difficult to include just the macros without using
//       `#[macro_use] extern crate nih_plug;`. That's why the macros are also re-exported from this
//       module.

/// Write something to the logger. This defaults to STDERR unless the user is running Windows and a
/// debugger has been attached, in which case `OutputDebugString()` will be used instead.
///
/// The logger's behavior can be controlled by setting the `NIH_LOG` environment variable to:
///
/// - `stderr`, in which case the log output always gets written to STDERR.
/// - `windbg` (only on Windows), in which case the output always gets logged using
///   `OutputDebugString()`.
/// - A file path, in which case the output gets appended to the end of that file which will be
///   created if necessary.
#[macro_export]
macro_rules! nih_log {
    ($($args:tt)*) => (
        $crate::log::info!($($args)*)
    );
}
#[doc(inline)]
pub use nih_log;

/// Similar to `nih_log!()`, but less subtle. Used for printing warnings.
#[macro_export]
macro_rules! nih_warn {
    ($($args:tt)*) => (
        $crate::log::warn!($($args)*)
    );
}
#[doc(inline)]
pub use nih_warn;

/// Similar to `nih_log!()`, but more scream-y. Used for printing fatal errors.
#[macro_export]
macro_rules! nih_error {
    ($($args:tt)*) => (
        $crate::log::error!($($args)*)
    );
}
#[doc(inline)]
pub use nih_error;

/// The same as `nih_log!()`, but with source and thread information. Like the
/// `nih_debug_assert*!()` macros, this is only shown when compiling in debug mode.
#[macro_export]
macro_rules! nih_trace {
    ($($args:tt)*) => (
        $crate::util::permit_alloc(|| $crate::log::trace!($($args)*))
    );
}
#[doc(inline)]
pub use nih_trace;

/// Analogues to the `dbg!()` macro, but respecting the `NIH_LOG` environment variable and with all
/// of the same logging features as the other `nih_*!()` macros. Like the `nih_debug_assert*!()`
/// macros, this is only shown when compiling in debug mode, but the macro will still return the
/// value in non-debug modes.
#[macro_export]
macro_rules! nih_dbg {
    () => {
        $crate::util::permit_alloc(|| $crate::log::debug!(""));
    };
    ($val:expr $(,)?) => {
        // Match here acts as a let-binding: https://stackoverflow.com/questions/48732263/why-is-rusts-assert-eq-implemented-using-a-match/48732525#48732525
        match $val {
            tmp => {
                $crate::util::permit_alloc(|| $crate::log::debug!("{} = {:#?}", stringify!($val), &tmp));
                tmp
            }
        }
    };
    ($($val:expr),+ $(,)?) => { ($($crate::nih_dbg!($val)),+,) };
}
#[doc(inline)]
pub use nih_dbg;

/// A `debug_assert!()` analogue that prints the error with line number information instead of
/// panicking. During tests this is upgraded to a regular panicking `debug_assert!()`.
///
/// TODO: Detect if we're running under a debugger, and trigger a break if we are
#[macro_export]
macro_rules! nih_debug_assert {
    ($cond:expr $(,)?) => (
        #[allow(clippy::neg_cmp_op_on_partial_ord)]
        if cfg!(test) {
           debug_assert!($cond);
        } else if cfg!(debug_assertions) && !$cond {
            $crate::util::permit_alloc(|| $crate::log::debug!(concat!("Debug assertion failed: ", stringify!($cond))));
        }
    );
    ($cond:expr, $format:expr $(, $($args:tt)*)?) => (
        #[allow(clippy::neg_cmp_op_on_partial_ord)]
        if cfg!(test) {
           debug_assert!($cond, $format, $($($args)*)?);
        } else if cfg!(debug_assertions) && !$cond {
            $crate::util::permit_alloc(|| $crate::log::debug!(concat!("Debug assertion failed: ", stringify!($cond), ", ", $format), $($($args)*)?));
        }
    );
}
#[doc(inline)]
pub use nih_debug_assert;

/// An unconditional debug assertion failure, for if the condition has already been checked
/// elsewhere. See [`nih_debug_assert!()`] for more information.
#[macro_export]
macro_rules! nih_debug_assert_failure {
    () => (
        if cfg!(test) {
           debug_assert!(false, "Debug assertion failed");
        } else if cfg!(debug_assertions) {
            $crate::util::permit_alloc(|| $crate::log::debug!("Debug assertion failed"));
        }
    );
    ($format:expr $(, $($args:tt)*)?) => (
        if cfg!(test) {
           debug_assert!(false, concat!("Debug assertion failed: ", $format), $($($args)*)?);
        } else if cfg!(debug_assertions) {
            $crate::util::permit_alloc(|| $crate::log::debug!(concat!("Debug assertion failed: ", $format), $($($args)*)?));
        }
    );
}
#[doc(inline)]
pub use nih_debug_assert_failure;

/// A `debug_assert_eq!()` analogue that prints the error with line number information instead of
/// panicking. See [`nih_debug_assert!()`] for more information.
#[macro_export]
macro_rules! nih_debug_assert_eq {
    ($left:expr, $right:expr $(,)?) => (
        #[allow(clippy::neg_cmp_op_on_partial_ord)]
        if cfg!(test) {
           debug_assert_eq!($left, $right);
        } else if cfg!(debug_assertions) && $left != $right {
            $crate::util::permit_alloc(|| $crate::log::debug!(concat!("Debug assertion failed: ", stringify!($left), " != ", stringify!($right))));
        }
    );
    ($left:expr, $right:expr, $format:expr $(, $($args:tt)*)?) => (
        #[allow(clippy::neg_cmp_op_on_partial_ord)]
        if cfg!(test) {
           debug_assert_eq!($left, $right, $format, $($($args)*)?);
        } else if cfg!(debug_assertions) && $left != $right {
            $crate::util::permit_alloc(|| $crate::log::debug!(concat!("Debug assertion failed: ", stringify!($left), " != ", stringify!($right), ", ", $format), $($($args)*)?));
        }
    );
}
#[doc(inline)]
pub use nih_debug_assert_eq;

/// A `debug_assert_ne!()` analogue that prints the error with line number information instead of
/// panicking. See [`nih_debug_assert!()`] for more information.
#[macro_export]
macro_rules! nih_debug_assert_ne {
    ($left:expr, $right:expr $(,)?) => (
        #[allow(clippy::neg_cmp_op_on_partial_ord)]
        if cfg!(test) {
           debug_assert_ne!($left, $right);
        } else if cfg!(debug_assertions) && $left == $right {
            $crate::util::permit_alloc(|| $crate::log::debug!(concat!("Debug assertion failed: ", stringify!($left), " == ", stringify!($right))));
        }
    );
    ($left:expr, $right:expr, $format:expr $(, $($args:tt)*)?) => (
        #[allow(clippy::neg_cmp_op_on_partial_ord)]
        if cfg!(test) {
           debug_assert_ne!($left, $right, $format, $($($args)*)?);
        } else if cfg!(debug_assertions) && $left == $right  {
            $crate::util::permit_alloc(|| $crate::log::debug!(concat!("Debug assertion failed: ", stringify!($left), " == ", stringify!($right), ", ", $format), $($($args)*)?));
        }
    );
}
#[doc(inline)]
pub use nih_debug_assert_ne;