metrique_writer_core/entry/
boxed.rs1use std::{any::Any, borrow::Cow, time::SystemTime};
5
6use smallvec::SmallVec;
7
8use crate::{
9 Entry, EntryWriter, Observation, Unit, ValidationError, Value, ValueWriter, value::MetricFlags,
10};
11
12use super::EntryConfig;
13
14pub struct BoxEntry(Box<dyn DynEntry>);
21
22impl BoxEntry {
23 pub fn new(entry: impl Entry + Send + 'static) -> Self {
25 Self(Box::new(entry))
26 }
27
28 pub fn inner(&self) -> &(dyn Any + Send + 'static) {
31 &self.0
32 }
33
34 pub fn inner_mut(&mut self) -> &mut (dyn Any + Send + 'static) {
37 &mut self.0
38 }
39}
40
41impl Entry for BoxEntry {
44 fn write<'a>(&'a self, writer: &mut impl EntryWriter<'a>) {
45 self.0.write(&mut EntryWriterToDyn(writer))
46 }
47
48 fn sample_group(&self) -> impl Iterator<Item = (Cow<'static, str>, Cow<'static, str>)> {
49 self.0.sample_group().into_iter()
50 }
51}
52
53trait DynEntry: Any + Send + 'static {
56 fn write<'a>(&'a self, writer: &mut dyn DynEntryWriter<'a>);
57 fn sample_group(&self) -> SmallVec<[(Cow<'static, str>, Cow<'static, str>); 2]>;
58}
59
60trait DynEntryWriter<'a> {
61 fn timestamp(&mut self, timestamp: SystemTime);
62 fn value(&mut self, name: Cow<'a, str>, value: &dyn DynValue);
63 fn config(&mut self, config: &'a dyn EntryConfig);
64}
65
66trait DynValue {
67 fn write(&self, writer: &mut dyn DynValueWriter);
68}
69
70trait DynValueWriter {
71 fn string(&mut self, value: &str);
72
73 fn metric<'a>(
74 &mut self,
75 distribution: &[Observation],
76 unit: Unit,
77 dimensions: &[(&'a str, &'a str)],
78 flags: MetricFlags<'_>,
79 );
80
81 fn error(&mut self, error: ValidationError);
82
83 fn values_str(&mut self, values: &[&str]);
84}
85
86impl<E: Entry + Send + 'static> DynEntry for E {
87 fn write<'a>(&'a self, writer: &mut dyn DynEntryWriter<'a>) {
88 Entry::write(self, &mut EntryWriterFromDyn(writer));
89 }
90
91 fn sample_group(&self) -> SmallVec<[(Cow<'static, str>, Cow<'static, str>); 2]> {
92 Entry::sample_group(self).collect()
93 }
94}
95
96struct EntryWriterToDyn<W>(W);
97struct EntryWriterFromDyn<'a, 'w>(&'w mut dyn DynEntryWriter<'a>);
98
99impl<'a, W: EntryWriter<'a>> DynEntryWriter<'a> for EntryWriterToDyn<W> {
100 fn timestamp(&mut self, timestamp: SystemTime) {
101 self.0.timestamp(timestamp)
102 }
103
104 fn value(&mut self, name: Cow<'a, str>, value: &dyn DynValue) {
105 self.0.value(name, &ValueFromDyn(value));
106 }
107
108 fn config(&mut self, config: &'a dyn EntryConfig) {
109 self.0.config(config);
110 }
111}
112
113impl<'a> EntryWriter<'a> for EntryWriterFromDyn<'a, '_> {
114 fn timestamp(&mut self, timestamp: SystemTime) {
115 self.0.timestamp(timestamp)
116 }
117
118 fn value(&mut self, name: impl Into<Cow<'a, str>>, value: &(impl Value + ?Sized)) {
119 self.0.value(name.into(), &ValueToDyn(value))
120 }
121
122 fn config(&mut self, config: &'a dyn EntryConfig) {
123 self.0.config(config)
124 }
125}
126
127struct ValueToDyn<'a, V: ?Sized>(&'a V);
128struct ValueFromDyn<'a>(&'a dyn DynValue);
129
130impl<V: Value + ?Sized> DynValue for ValueToDyn<'_, V> {
131 fn write(&self, writer: &mut dyn DynValueWriter) {
132 self.0.write(ValueWriterFromDyn(writer));
133 }
134}
135
136impl Value for ValueFromDyn<'_> {
137 fn write(&self, writer: impl ValueWriter) {
138 self.0.write(&mut ValueWriterToDyn(Some(writer)));
139 }
140}
141
142struct ValueWriterToDyn<W>(Option<W>);
143struct ValueWriterFromDyn<'a>(&'a mut dyn DynValueWriter);
144
145impl<W: ValueWriter> DynValueWriter for ValueWriterToDyn<W> {
146 fn string(&mut self, value: &str) {
147 self.0.take().unwrap().string(value)
148 }
149
150 fn metric<'a>(
151 &mut self,
152 distribution: &[Observation],
153 unit: Unit,
154 dimensions: &[(&'a str, &'a str)],
155 flags: MetricFlags<'_>,
156 ) {
157 self.0.take().unwrap().metric(
158 distribution.iter().copied(),
159 unit,
160 dimensions.iter().copied(),
161 flags,
162 )
163 }
164
165 fn error(&mut self, error: ValidationError) {
166 self.0.take().unwrap().error(error)
167 }
168
169 fn values_str(&mut self, values: &[&str]) {
170 self.0.take().unwrap().values(values.iter())
171 }
172}
173
174impl ValueWriter for ValueWriterFromDyn<'_> {
175 fn string(self, value: &str) {
176 self.0.string(value)
177 }
178
179 fn metric<'a>(
180 self,
181 distribution: impl IntoIterator<Item = Observation>,
182 unit: Unit,
183 dimensions: impl IntoIterator<Item = (&'a str, &'a str)>,
184 flags: MetricFlags<'_>,
185 ) {
186 self.0.metric(
187 distribution
188 .into_iter()
189 .collect::<SmallVec<[_; 2]>>()
190 .as_slice(),
191 unit,
192 dimensions
193 .into_iter()
194 .collect::<SmallVec<[_; 1]>>()
195 .as_slice(),
196 flags,
197 )
198 }
199
200 fn error(self, error: ValidationError) {
201 self.0.error(error)
202 }
203
204 fn values<'a, V: Value + 'a>(self, values: impl IntoIterator<Item = &'a V>) {
205 let strs: SmallVec<[String; 8]> = values
206 .into_iter()
207 .filter_map(|v| {
208 let mut s = String::new();
209 v.write(crate::value::StringCapture(&mut s));
210 if s.is_empty() { None } else { Some(s) }
211 })
212 .collect();
213 let refs: SmallVec<[&str; 8]> = strs.iter().map(|s| s.as_str()).collect();
214 self.0.values_str(&refs)
215 }
216}
217
218#[cfg(test)]
219mod tests {
220 use super::*;
221 use crate::{
222 EntryWriter, MetricValue as _, test_stream::DummyEntryWriter, value::WithDimensions,
223 };
224 use std::time::{Duration, SystemTime};
225
226 #[test]
227 fn dummy() {
228 struct TestEntry;
229 impl Entry for TestEntry {
230 fn write<'a>(&'a self, writer: &mut impl EntryWriter<'a>) {
231 writer.timestamp(SystemTime::UNIX_EPOCH + Duration::from_secs_f64(1.5));
232 writer.value("Time", &Duration::from_millis(42));
233 writer.value("StringProp", "some string value");
234 writer.value("BasicIntCount", &1234u64);
235 writer.value(
236 "BasicIntCountWithDimensions",
237 &(1234u64.with_dimensions([("A", "x"), ("B", "y")]) as WithDimensions<_, 2>),
238 );
239 writer.value("BasicFloatCount", &5.4321f64);
240 writer.value("SomeDuration", &Duration::from_micros(12345678));
241 }
242 }
243
244 let mut writer = DummyEntryWriter::default();
245 <BoxEntry as Entry>::write(&TestEntry.boxed(), &mut writer);
246 assert_eq!(
247 writer.0,
248 vec![
249 ("timestamp".to_string(), "1.5".to_string()),
250 (
251 "Time".to_string(),
252 "[Floating(42.0)] Milliseconds []".to_string()
253 ),
254 ("StringProp".to_string(), "some string value".to_string()),
255 (
256 "BasicIntCount".to_string(),
257 "[Unsigned(1234)] None []".to_string()
258 ),
259 (
260 "BasicIntCountWithDimensions".to_string(),
261 "[Unsigned(1234)] None [(\"A\", \"x\"), (\"B\", \"y\")]".to_string()
262 ),
263 (
264 "BasicFloatCount".to_string(),
265 "[Floating(5.4321)] None []".to_string()
266 ),
267 (
268 "SomeDuration".to_string(),
269 "[Floating(12345.678)] Milliseconds []".to_string()
270 ),
271 ]
272 );
273 }
274}