ccs2/
tracer.rs

1use std::{ops::Deref, sync::Arc};
2
3use crate::{SearchError, ast::PropertyValue, search::DisplayContext};
4
5/// A callback which is called by the [`Context`] when a property is found
6///
7/// Provides debug information about the current context's constraints under which the property was
8/// found.
9///
10/// [`Context`]: crate::Context
11pub trait PropertyTracer: Send + Sync {
12    fn on_found(&self, name: &str, value: &PropertyValue, context: DisplayContext);
13    fn on_error(&self, error: SearchError);
14}
15
16pub trait ClonablePropertyTracer: PropertyTracer + Clone {}
17impl<T: PropertyTracer + Clone> ClonablePropertyTracer for T {}
18
19impl<T: ?Sized + PropertyTracer> PropertyTracer for Arc<T> {
20    fn on_found(&self, name: &str, value: &PropertyValue, context: DisplayContext) {
21        self.deref().on_found(name, value, context)
22    }
23
24    fn on_error(&self, error: SearchError) {
25        self.deref().on_error(error);
26    }
27}
28// impl<T: PropertyTracerImpl + Clone> PropertyTracer for Arc<T> {}
29
30/// A [`PropertyTracer`] that does nothing
31#[derive(Clone)]
32pub struct NullTracer();
33impl PropertyTracer for NullTracer {
34    fn on_found(&self, _name: &str, _value: &PropertyValue, _context: DisplayContext) {}
35    fn on_error(&self, _error: SearchError) {}
36}
37
38#[cfg(feature = "log")]
39pub(crate) mod log {
40    use super::*;
41
42    /// A [`PropertyTracer`] that logs when and where properties are found
43    ///
44    /// Requires the `log` feature
45    #[derive(Clone)]
46    pub struct LogTracer {
47        pub success_level: ::log::Level,
48        pub error_level: ::log::Level,
49    }
50    impl LogTracer {
51        pub fn single_level(level: ::log::Level) -> Self {
52            LogTracer {
53                success_level: level,
54                error_level: level,
55            }
56        }
57    }
58
59    impl PropertyTracer for LogTracer {
60        fn on_found(&self, name: &str, value: &PropertyValue, context: DisplayContext) {
61            ::log::log!(
62                self.success_level,
63                "Found property: {name} = {}\n\t{context}\n\torigin: {}",
64                value.value,
65                value.origin
66            );
67        }
68
69        fn on_error(&self, error: SearchError) {
70            match error {
71                SearchError::MissingPropertyError { name, context } => {
72                    ::log::log!(self.error_level, "Property not found: {name}\n\t{context}");
73                }
74                SearchError::EmptyPropertyError { name, context } => {
75                    ::log::log!(
76                        self.error_level,
77                        "Empty property found: {name}\n\t{context}"
78                    );
79                }
80                SearchError::AmbiguousPropertyError {
81                    count,
82                    name,
83                    context,
84                } => {
85                    ::log::log!(
86                        self.error_level,
87                        "Ambiguous property found ({count} values): {name}\n\t{context}"
88                    );
89                }
90            }
91        }
92    }
93}