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