tracing_capture/predicates/
field.rs
1use predicates::{
4 reflection::{Case, PredicateReflection, Product},
5 Predicate,
6};
7
8use std::{any::type_name, borrow::Borrow, fmt, marker::PhantomData};
9
10use crate::{Captured, CapturedEvent};
11use tracing_tunnel::{FromTracedValue, TracedValue};
12
13pub trait IntoFieldPredicate {
15 type Predicate: Predicate<TracedValue>;
18 fn into_predicate(self) -> Self::Predicate;
20}
21
22impl<P: Predicate<TracedValue>> IntoFieldPredicate for [P; 1] {
23 type Predicate = P;
24
25 fn into_predicate(self) -> Self::Predicate {
26 self.into_iter().next().unwrap()
27 }
28}
29
30macro_rules! impl_into_field_predicate {
31 ($($ty:ty),+) => {
32 $(
33 impl IntoFieldPredicate for $ty {
34 type Predicate = EquivPredicate<Self>;
35
36 fn into_predicate(self) -> Self::Predicate {
37 EquivPredicate { value: self }
38 }
39 }
40 )+
41 };
42}
43
44impl_into_field_predicate!(bool, i64, i128, u64, u128, f64, &str);
45
46pub fn field<P: IntoFieldPredicate>(
83 name: &'static str,
84 matches: P,
85) -> FieldPredicate<P::Predicate> {
86 FieldPredicate {
87 name,
88 matches: matches.into_predicate(),
89 }
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq)]
97pub struct FieldPredicate<P> {
98 name: &'static str,
99 matches: P,
100}
101
102impl_bool_ops!(FieldPredicate<P>);
103
104impl<P: Predicate<TracedValue>> fmt::Display for FieldPredicate<P> {
105 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
106 write!(formatter, "fields.{}({})", self.name, self.matches)
107 }
108}
109
110impl<P: Predicate<TracedValue>> PredicateReflection for FieldPredicate<P> {}
111
112impl<'a, P: Predicate<TracedValue>, T: Captured<'a>> Predicate<T> for FieldPredicate<P> {
113 fn eval(&self, variable: &T) -> bool {
114 variable
115 .value(self.name)
116 .map_or(false, |value| self.matches.eval(value))
117 }
118
119 fn find_case(&self, expected: bool, variable: &T) -> Option<Case<'_>> {
120 let value = if let Some(value) = variable.value(self.name) {
121 value
122 } else {
123 return if expected {
124 None } else {
126 let product = Product::new(format!("fields.{}", self.name), "None");
127 Some(Case::new(Some(self), expected).add_product(product))
128 };
129 };
130
131 let child = self.matches.find_case(expected, value)?;
132 Some(Case::new(Some(self), expected).add_child(child))
133 }
134}
135
136#[doc(hidden)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
138pub struct EquivPredicate<V> {
139 value: V,
140}
141
142impl<V: fmt::Debug> fmt::Display for EquivPredicate<V> {
143 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
144 write!(formatter, "var == {:?}", self.value)
145 }
146}
147
148impl<V: fmt::Debug> PredicateReflection for EquivPredicate<V> {}
149
150impl<V: fmt::Debug + PartialEq<TracedValue>> Predicate<TracedValue> for EquivPredicate<V> {
151 fn eval(&self, variable: &TracedValue) -> bool {
152 self.value == *variable
153 }
154
155 fn find_case(&self, expected: bool, variable: &TracedValue) -> Option<Case<'_>> {
156 if self.eval(variable) == expected {
157 let product = Product::new("var", format!("{variable:?}"));
158 Some(Case::new(Some(self), expected).add_product(product))
159 } else {
160 None
161 }
162 }
163}
164
165pub fn value<T, P>(matches: P) -> ValuePredicate<T, P>
188where
189 T: for<'a> FromTracedValue<'a> + ?Sized,
190 P: Predicate<T>,
191{
192 ValuePredicate {
193 matches,
194 _ty: PhantomData,
195 }
196}
197
198#[derive(Debug)]
200pub struct ValuePredicate<T: ?Sized, P> {
201 matches: P,
202 _ty: PhantomData<fn(T)>,
203}
204
205impl<T: ?Sized, P: Clone> Clone for ValuePredicate<T, P> {
206 fn clone(&self) -> Self {
207 Self {
208 matches: self.matches.clone(),
209 _ty: PhantomData,
210 }
211 }
212}
213
214impl<T: ?Sized, P: Copy> Copy for ValuePredicate<T, P> {}
215
216impl<T: ?Sized, P: PartialEq> PartialEq for ValuePredicate<T, P> {
217 fn eq(&self, other: &Self) -> bool {
218 self.matches == other.matches
219 }
220}
221
222impl<T, P> fmt::Display for ValuePredicate<T, P>
223where
224 T: for<'a> FromTracedValue<'a> + ?Sized,
225 P: Predicate<T>,
226{
227 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
228 write!(formatter, "is<{}>({})", type_name::<T>(), self.matches)
229 }
230}
231
232impl<T, P> PredicateReflection for ValuePredicate<T, P>
233where
234 T: for<'a> FromTracedValue<'a> + ?Sized,
235 P: Predicate<T>,
236{
237}
238
239impl<T, P> Predicate<TracedValue> for ValuePredicate<T, P>
240where
241 T: for<'a> FromTracedValue<'a> + ?Sized,
242 P: Predicate<T>,
243{
244 fn eval(&self, variable: &TracedValue) -> bool {
245 T::from_value(variable).map_or(false, |value| self.matches.eval(value.borrow()))
246 }
247
248 fn find_case(&self, expected: bool, variable: &TracedValue) -> Option<Case<'_>> {
249 let value = T::from_value(variable);
250 let value = if let Some(value) = &value {
251 value.borrow()
252 } else {
253 return if expected {
254 None } else {
256 let product = Product::new(format!("var.as<{}>", type_name::<T>()), "None");
257 Some(Case::new(Some(self), expected).add_product(product))
258 };
259 };
260
261 let child = self.matches.find_case(expected, value)?;
262 Some(Case::new(Some(self), expected).add_child(child))
263 }
264}
265
266impl<T, P> IntoFieldPredicate for ValuePredicate<T, P>
267where
268 T: for<'a> FromTracedValue<'a> + ?Sized,
269 P: Predicate<T>,
270{
271 type Predicate = Self;
272
273 fn into_predicate(self) -> Self::Predicate {
274 self
275 }
276}
277
278pub fn message<P: Predicate<str>>(matches: P) -> MessagePredicate<P> {
305 MessagePredicate { matches }
306}
307
308#[derive(Debug, Clone, Copy, PartialEq, Eq)]
310pub struct MessagePredicate<P> {
311 matches: P,
312}
313
314impl_bool_ops!(MessagePredicate<P>);
315
316impl<P: Predicate<str>> fmt::Display for MessagePredicate<P> {
317 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
318 write!(formatter, "message({})", self.matches)
319 }
320}
321
322impl<P: Predicate<str>> PredicateReflection for MessagePredicate<P> {}
323
324impl<P: Predicate<str>> Predicate<CapturedEvent<'_>> for MessagePredicate<P> {
325 fn eval(&self, variable: &CapturedEvent<'_>) -> bool {
326 variable
327 .message()
328 .map_or(false, |value| self.matches.eval(value))
329 }
330
331 fn find_case(&self, expected: bool, variable: &CapturedEvent<'_>) -> Option<Case<'_>> {
332 let message = if let Some(message) = variable.message() {
333 message
334 } else {
335 return if expected {
336 None } else {
338 let product = Product::new("message", "None");
339 Some(Case::new(Some(self), expected).add_product(product))
340 };
341 };
342
343 let child = self.matches.find_case(expected, message)?;
344 Some(Case::new(Some(self), expected).add_child(child))
345 }
346}