1mod json;
11mod kv;
12mod map;
13mod plain;
14
15pub use json::JsonEvent;
16pub use kv::KvEvent;
17pub use map::MapEvent;
18pub use plain::PlainEvent;
19
20use std::borrow::Cow;
21
22use serde_json::Value;
23
24#[derive(Debug, Clone, PartialEq)]
34pub enum EventValue<'a> {
35 Str(Cow<'a, str>),
36 Int(i64),
37 Float(f64),
38 Bool(bool),
39 Null,
40 Array(Vec<EventValue<'a>>),
41 Map(Vec<(Cow<'a, str>, EventValue<'a>)>),
42}
43
44impl<'a> EventValue<'a> {
45 #[inline]
47 pub fn as_str(&self) -> Option<Cow<'_, str>> {
48 match self {
49 EventValue::Str(s) => Some(Cow::Borrowed(s)),
50 EventValue::Int(n) => Some(Cow::Owned(n.to_string())),
51 EventValue::Float(f) => Some(Cow::Owned(f.to_string())),
52 EventValue::Bool(b) => Some(Cow::Borrowed(if *b { "true" } else { "false" })),
53 _ => None,
54 }
55 }
56
57 #[inline]
59 pub fn as_f64(&self) -> Option<f64> {
60 match self {
61 EventValue::Float(f) => Some(*f),
62 EventValue::Int(n) => Some(*n as f64),
63 EventValue::Str(s) => s.parse().ok(),
64 _ => None,
65 }
66 }
67
68 #[inline]
70 pub fn as_i64(&self) -> Option<i64> {
71 match self {
72 EventValue::Int(n) => Some(*n),
73 EventValue::Float(f) => {
74 let truncated = *f as i64;
75 if (truncated as f64 - f).abs() < f64::EPSILON {
76 Some(truncated)
77 } else {
78 None
79 }
80 }
81 EventValue::Str(s) => s.parse().ok(),
82 _ => None,
83 }
84 }
85
86 #[inline]
88 pub fn as_bool(&self) -> Option<bool> {
89 match self {
90 EventValue::Bool(b) => Some(*b),
91 EventValue::Str(s) => match s.to_lowercase().as_str() {
92 "true" | "1" | "yes" => Some(true),
93 "false" | "0" | "no" => Some(false),
94 _ => None,
95 },
96 _ => None,
97 }
98 }
99
100 #[inline]
101 pub fn is_null(&self) -> bool {
102 matches!(self, EventValue::Null)
103 }
104
105 pub fn to_json(&self) -> Value {
107 match self {
108 EventValue::Str(s) => Value::String(s.to_string()),
109 EventValue::Int(n) => Value::Number((*n).into()),
110 EventValue::Float(f) => {
111 serde_json::Number::from_f64(*f).map_or(Value::Null, Value::Number)
112 }
113 EventValue::Bool(b) => Value::Bool(*b),
114 EventValue::Null => Value::Null,
115 EventValue::Array(arr) => Value::Array(arr.iter().map(|v| v.to_json()).collect()),
116 EventValue::Map(entries) => {
117 let map = entries
118 .iter()
119 .map(|(k, v)| (k.to_string(), v.to_json()))
120 .collect();
121 Value::Object(map)
122 }
123 }
124 }
125}
126
127impl<'a> From<&'a Value> for EventValue<'a> {
128 fn from(v: &'a Value) -> Self {
129 match v {
130 Value::String(s) => EventValue::Str(Cow::Borrowed(s.as_str())),
131 Value::Number(n) => {
132 if let Some(i) = n.as_i64() {
133 EventValue::Int(i)
134 } else {
135 EventValue::Float(n.as_f64().unwrap_or(f64::NAN))
136 }
137 }
138 Value::Bool(b) => EventValue::Bool(*b),
139 Value::Null => EventValue::Null,
140 Value::Array(arr) => EventValue::Array(arr.iter().map(EventValue::from).collect()),
141 Value::Object(map) => EventValue::Map(
142 map.iter()
143 .map(|(k, v)| (Cow::Borrowed(k.as_str()), EventValue::from(v)))
144 .collect(),
145 ),
146 }
147 }
148}
149
150pub trait Event {
159 fn get_field(&self, path: &str) -> Option<EventValue<'_>>;
164
165 fn any_string_value(&self, pred: &dyn Fn(&str) -> bool) -> bool;
168
169 fn all_string_values(&self) -> Vec<Cow<'_, str>>;
171
172 fn to_json(&self) -> Value;
174}
175
176impl<T: Event + ?Sized> Event for &T {
177 fn get_field(&self, path: &str) -> Option<EventValue<'_>> {
178 (**self).get_field(path)
179 }
180
181 fn any_string_value(&self, pred: &dyn Fn(&str) -> bool) -> bool {
182 (**self).any_string_value(pred)
183 }
184
185 fn all_string_values(&self) -> Vec<Cow<'_, str>> {
186 (**self).all_string_values()
187 }
188
189 fn to_json(&self) -> Value {
190 (**self).to_json()
191 }
192}
193
194#[cfg(test)]
195mod tests {
196 use super::*;
197 use serde_json::json;
198
199 #[test]
200 fn event_value_as_str() {
201 assert_eq!(EventValue::Str(Cow::Borrowed("hi")).as_str().unwrap(), "hi");
202 assert_eq!(EventValue::Int(42).as_str().unwrap(), "42");
203 assert_eq!(EventValue::Float(2.71).as_str().unwrap(), "2.71");
204 assert_eq!(EventValue::Bool(true).as_str().unwrap(), "true");
205 assert!(EventValue::Null.as_str().is_none());
206 }
207
208 #[test]
209 fn event_value_as_f64() {
210 assert_eq!(EventValue::Float(2.71).as_f64(), Some(2.71));
211 assert_eq!(EventValue::Int(42).as_f64(), Some(42.0));
212 assert_eq!(EventValue::Str(Cow::Borrowed("1.5")).as_f64(), Some(1.5));
213 assert!(EventValue::Bool(true).as_f64().is_none());
214 }
215
216 #[test]
217 fn event_value_as_i64() {
218 assert_eq!(EventValue::Int(42).as_i64(), Some(42));
219 assert_eq!(EventValue::Float(42.0).as_i64(), Some(42));
220 assert_eq!(EventValue::Float(42.5).as_i64(), None);
221 assert_eq!(EventValue::Str(Cow::Borrowed("100")).as_i64(), Some(100));
222 }
223
224 #[test]
225 fn event_value_to_json() {
226 assert_eq!(EventValue::Str(Cow::Borrowed("hi")).to_json(), json!("hi"));
227 assert_eq!(EventValue::Int(42).to_json(), json!(42));
228 assert_eq!(EventValue::Bool(true).to_json(), json!(true));
229 assert_eq!(EventValue::Null.to_json(), Value::Null);
230 }
231}