1use crate::Record;
2use crate::RecordKind;
3use itertools::Itertools;
4
5pub trait RecordFilter: Send + 'static {
17 fn check(&self, record: &Record) -> bool;
22}
23
24impl RecordFilter for Box<dyn RecordFilter> {
25 fn check(&self, record: &Record) -> bool {
26 (**self).check(record)
27 }
28}
29
30#[derive(Debug, Clone, Copy, Default)]
39pub struct DefaultFilter;
40
41impl RecordFilter for DefaultFilter {
42 #[inline]
43 fn check(&self, _record: &Record) -> bool {
44 true
45 }
46}
47
48impl RecordFilter for Box<DefaultFilter> {
49 fn check(&self, record: &Record) -> bool {
50 (**self).check(record)
51 }
52}
53
54#[derive(Debug)]
65pub struct RecordKindFilter {
66 allowed_kinds: Vec<RecordKind>,
67}
68
69impl RecordKindFilter {
70 pub fn new(kinds: &'static [RecordKind]) -> Self {
72 Self {
73 allowed_kinds: kinds.iter().copied().unique().collect(),
74 }
75 }
76}
77
78impl RecordFilter for RecordKindFilter {
79 #[inline]
80 fn check(&self, record: &Record) -> bool {
81 self.allowed_kinds.contains(&record.kind)
82 }
83}
84
85impl RecordFilter for Box<RecordKindFilter> {
86 fn check(&self, record: &Record) -> bool {
87 (**self).check(record)
88 }
89}
90
91#[cfg(test)]
96mod tests {
97 use crate::filter::DefaultFilter;
98 use crate::filter::RecordFilter;
99 use crate::filter::RecordKindFilter;
100 use crate::record::Record;
101 use crate::record::RecordKind;
102
103 fn assert_unpin<T: Unpin>() {}
104
105 #[test]
106 fn test_unpin() {
107 assert_unpin::<DefaultFilter>();
108 assert_unpin::<RecordKindFilter>();
109 }
110
111 #[test]
112 fn test_default_filter() {
113 assert!(DefaultFilter.check(&Record::new(
114 RecordKind::Read,
115 String::from("01:02:03:04:05:06")
116 )));
117 assert!(DefaultFilter.check(&Record::new(
118 RecordKind::Write,
119 String::from("01:02:03:04:05:06")
120 )));
121 assert!(DefaultFilter.check(&Record::new(RecordKind::Drop, String::from("deallocated"))));
122 assert!(DefaultFilter.check(&Record::new(
123 RecordKind::Shutdown,
124 String::from("write shutdown request")
125 )));
126 }
127
128 #[test]
129 fn test_record_kind_filter() {
130 let filter = RecordKindFilter::new(&[RecordKind::Read]);
131 assert!(filter.check(&Record::new(
132 RecordKind::Read,
133 String::from("01:02:03:04:05:06")
134 )));
135 assert!(!filter.check(&Record::new(
136 RecordKind::Write,
137 String::from("01:02:03:04:05:06")
138 )));
139 assert!(!filter.check(&Record::new(RecordKind::Drop, String::from("deallocated"))));
140 assert!(!filter.check(&Record::new(
141 RecordKind::Shutdown,
142 String::from("write shutdown request")
143 )));
144 }
145
146 #[test]
147 fn test_trait_object_safety() {
148 let default: Box<dyn RecordFilter> = Box::<DefaultFilter>::default();
150 let record_kind: Box<dyn RecordFilter> = Box::new(RecordKindFilter::new(&[]));
151
152 let record = Record::new(RecordKind::Open, String::from("test log record"));
153
154 _ = default.check(&record);
156 _ = record_kind.check(&record);
157 }
158
159 fn assert_record_filter<T: RecordFilter>() {}
160
161 #[test]
162 fn test_box() {
163 assert_record_filter::<Box<dyn RecordFilter>>();
164 assert_record_filter::<Box<RecordKindFilter>>();
165 assert_record_filter::<Box<DefaultFilter>>();
166 }
167
168 fn assert_send<T: Send>() {}
169
170 #[test]
171 fn test_send() {
172 assert_send::<RecordKindFilter>();
173 assert_send::<DefaultFilter>();
174
175 assert_send::<Box<dyn RecordFilter>>();
176 assert_send::<Box<RecordKindFilter>>();
177 assert_send::<Box<DefaultFilter>>();
178 }
179}