1 use std::sync::atomic::{AtomicUsize, Ordering};
2 
3 use libc::c_char;
4 
5 use crate::{panic, raw, util::Binding};
6 
7 /// Available tracing levels.  When tracing is set to a particular level,
8 /// callers will be provided tracing at the given level and all lower levels.
9 #[derive(Copy, Clone, Debug)]
10 pub enum TraceLevel {
11     /// No tracing will be performed.
12     None,
13 
14     /// Severe errors that may impact the program's execution
15     Fatal,
16 
17     /// Errors that do not impact the program's execution
18     Error,
19 
20     /// Warnings that suggest abnormal data
21     Warn,
22 
23     /// Informational messages about program execution
24     Info,
25 
26     /// Detailed data that allows for debugging
27     Debug,
28 
29     /// Exceptionally detailed debugging data
30     Trace,
31 }
32 
33 impl Binding for TraceLevel {
34     type Raw = raw::git_trace_level_t;
from_raw(raw: raw::git_trace_level_t) -> Self35     unsafe fn from_raw(raw: raw::git_trace_level_t) -> Self {
36         match raw {
37             raw::GIT_TRACE_NONE => Self::None,
38             raw::GIT_TRACE_FATAL => Self::Fatal,
39             raw::GIT_TRACE_ERROR => Self::Error,
40             raw::GIT_TRACE_WARN => Self::Warn,
41             raw::GIT_TRACE_INFO => Self::Info,
42             raw::GIT_TRACE_DEBUG => Self::Debug,
43             raw::GIT_TRACE_TRACE => Self::Trace,
44             _ => panic!("Unknown git trace level"),
45         }
46     }
raw(&self) -> raw::git_trace_level_t47     fn raw(&self) -> raw::git_trace_level_t {
48         match *self {
49             Self::None => raw::GIT_TRACE_NONE,
50             Self::Fatal => raw::GIT_TRACE_FATAL,
51             Self::Error => raw::GIT_TRACE_ERROR,
52             Self::Warn => raw::GIT_TRACE_WARN,
53             Self::Info => raw::GIT_TRACE_INFO,
54             Self::Debug => raw::GIT_TRACE_DEBUG,
55             Self::Trace => raw::GIT_TRACE_TRACE,
56         }
57     }
58 }
59 
60 //TODO: pass raw &[u8] and leave conversion to consumer (breaking API)
61 /// Callback type used to pass tracing events to the subscriber.
62 /// see `trace_set` to register a scubscriber.
63 pub type TracingCb = fn(TraceLevel, &str);
64 
65 static CALLBACK: AtomicUsize = AtomicUsize::new(0);
66 
67 ///
trace_set(level: TraceLevel, cb: TracingCb) -> bool68 pub fn trace_set(level: TraceLevel, cb: TracingCb) -> bool {
69     CALLBACK.store(cb as usize, Ordering::SeqCst);
70 
71     unsafe {
72         raw::git_trace_set(level.raw(), Some(tracing_cb_c));
73     }
74 
75     return true;
76 }
77 
tracing_cb_c(level: raw::git_trace_level_t, msg: *const c_char)78 extern "C" fn tracing_cb_c(level: raw::git_trace_level_t, msg: *const c_char) {
79     let cb = CALLBACK.load(Ordering::SeqCst);
80     panic::wrap(|| unsafe {
81         let cb: TracingCb = std::mem::transmute(cb);
82         let msg = std::ffi::CStr::from_ptr(msg).to_string_lossy();
83         cb(Binding::from_raw(level), msg.as_ref());
84     });
85 }
86