cvlr_log/
log.rs

1use crate::CvlrLogger;
2
3pub trait CvlrLog {
4    fn log(&self, tag: &str, logger: &mut CvlrLogger);
5}
6
7#[inline(always)]
8pub fn cvlr_log_with<T: CvlrLog>(tag: &str, val: &T, logger: &mut CvlrLogger) {
9    val.log(tag, logger);
10}
11
12#[inline(always)]
13pub fn cvlr_log<T: CvlrLog>(tag: &str, val: &T) {
14    let mut logger = CvlrLogger::new();
15    val.log(tag, &mut logger);
16}
17
18#[cfg(not(feature = "no-loc"))]
19#[macro_export]
20macro_rules! cvlr_log_core_file {
21    () => {
22        ::core::file!()
23    };
24}
25
26#[cfg(not(feature = "no-loc"))]
27#[macro_export]
28macro_rules! cvlr_log_core_line {
29    () => {
30        ::core::line!()
31    };
32}
33
34#[cfg(feature = "no-loc")]
35#[macro_export]
36macro_rules! cvlr_log_core_file {
37    () => {
38        "<FILE>"
39    };
40}
41
42#[cfg(feature = "no-loc")]
43#[macro_export]
44macro_rules! cvlr_log_core_line {
45    () => {
46        0u32
47    };
48}
49
50#[macro_export]
51macro_rules! cvlr_log {
52    () => {
53        $crate::log_loc($crate::cvlr_log_core_file!(), $crate::cvlr_log_core_line!());
54    };
55
56    // log with a specified logger
57    ($v:expr => $t:expr ; $logger:ident) => {
58        $crate::cvlr_log_with($t, &($v), &mut $logger)
59    };
60
61    // multiple values with explicit tags
62    ($v:expr => $t:expr, $( $vs:expr => $ts:expr ),+ $(,)?) => {
63        $crate::cvlr_log! { $v => $t }
64        $crate::cvlr_log! { $( $vs => $ts ),+ }
65    };
66
67    // first labeled, rest can be mixed (labeled or unlabeled)
68    ($v:expr => $t:expr, $( $rest:tt )+) => {
69        $crate::cvlr_log! { $v => $t }
70        $crate::cvlr_log! { $( $rest )+ }
71    };
72
73    ($v:expr => $t:expr) => {
74        // TODO: enable when this becomes stable
75        // $crate::add_loc(core::file!(), core::line!());
76        $crate::cvlr_log($t, &($v));
77    };
78
79    ($v:expr $(,)?) => {
80        $crate::cvlr_log! { $v => stringify!($v) }
81    };
82
83    // first unlabeled, rest can be mixed (labeled or unlabeled)
84    ($v:expr, $( $rest:tt )+) => {
85        $crate::cvlr_log! { $v }
86        $crate::cvlr_log! { $( $rest )+ }
87    };
88}
89
90pub use cvlr_log as clog;
91
92macro_rules! impl_cvlr_log_for_uint {
93    ($t:ty) => {
94        impl CvlrLog for $t {
95            #[inline(always)]
96            fn log(&self, tag: &str, logger: &mut CvlrLogger) {
97                logger.log_u64(tag, *self as u64);
98            }
99        }
100    };
101}
102
103impl_cvlr_log_for_uint!(bool);
104impl_cvlr_log_for_uint!(u8);
105impl_cvlr_log_for_uint!(u16);
106impl_cvlr_log_for_uint!(u32);
107impl_cvlr_log_for_uint!(u64);
108impl_cvlr_log_for_uint!(usize);
109
110impl CvlrLog for u128 {
111    #[inline(always)]
112    fn log(&self, tag: &str, logger: &mut CvlrLogger) {
113        logger.log_u128(tag, *self);
114    }
115}
116
117macro_rules! impl_cvlr_log_for_int {
118    ($t:ty) => {
119        impl CvlrLog for $t {
120            #[inline(always)]
121            fn log(&self, tag: &str, logger: &mut CvlrLogger) {
122                logger.log_i64(tag, *self as i64);
123            }
124        }
125    };
126}
127
128impl_cvlr_log_for_int!(i8);
129impl_cvlr_log_for_int!(i16);
130impl_cvlr_log_for_int!(i32);
131impl_cvlr_log_for_int!(i64);
132
133impl CvlrLog for i128 {
134    #[inline(always)]
135    fn log(&self, tag: &str, logger: &mut CvlrLogger) {
136        logger.log_i128(tag, *self);
137    }
138}
139
140impl<T: CvlrLog> CvlrLog for &T {
141    #[inline(always)]
142    fn log(&self, tag: &str, logger: &mut CvlrLogger) {
143        (**self).log(tag, logger);
144    }
145}
146
147impl CvlrLog for &str {
148    #[inline(always)]
149    fn log(&self, _tag: &str, logger: &mut CvlrLogger) {
150        logger.log(self);
151    }
152}
153
154impl CvlrLog for () {
155    #[inline(always)]
156    fn log(&self, tag: &str, logger: &mut CvlrLogger) {
157        logger.log_str(tag, "()");
158    }
159}
160
161impl<T: CvlrLog> CvlrLog for Option<T> {
162    #[inline(always)]
163    fn log(&self, tag: &str, logger: &mut CvlrLogger) {
164        if let Some(v) = self {
165            v.log(tag, logger);
166        } else {
167            logger.log_str(tag, "None");
168        }
169    }
170}
171
172impl<T: CvlrLog, E: CvlrLog> CvlrLog for Result<T, E> {
173    #[inline(always)]
174    fn log(&self, tag: &str, logger: &mut CvlrLogger) {
175        match self {
176            Ok(v) => {
177                logger.log("Ok");
178                v.log(tag, logger)
179            }
180            Err(v) => {
181                logger.log("Err");
182                v.log(tag, logger)
183            }
184        }
185    }
186}
187
188#[cfg(feature = "mathint")]
189impl CvlrLog for cvlr_mathint::NativeInt {
190    #[inline(always)]
191    fn log(&self, tag: &str, logger: &mut CvlrLogger) {
192        logger.log_u64(tag, self.as_internal());
193    }
194}
195
196/// Implements CvlrLog trait given a struct and a list of fields
197///
198/// Example usage
199/// ```
200/// use cvlr_log::impl_cvlr_log_for_struct;
201/// struct Foo {
202///     x: u64,
203///     y: u64,
204/// }
205/// impl_cvlr_log_for_struct!(Foo, x, y,);
206/// ```
207#[macro_export]
208macro_rules! impl_cvlr_log_for_struct {
209    ($prop:path $(, $field:ident)* $(,)?) => {
210        impl $crate::CvlrLog for $prop {
211            fn log(&self, tag: &str, logger: &mut $crate::CvlrLogger) {
212                logger.log_scope_start(tag);
213                let __self = self;
214                $(impl_cvlr_log_for_struct!(@field __self, logger, $field);)*
215                logger.log_scope_end(tag);
216            }
217        }
218    };
219
220    (@field $self:ident, $logger:ident, $field:ident) => {
221        $crate::cvlr_log_with(stringify!($field), &$self.$field, $logger);
222    };
223}
224
225pub use impl_cvlr_log_for_struct as impl_clog_for_struct;