1use core::time::Duration;
7use std::marker::PhantomData;
8use std::sync::{Arc, MutexGuard};
9use std::time::SystemTime;
10use std::{borrow::Cow, sync::Mutex};
11
12use metrique_writer_core::EntryWriter;
13use metrique_writer_core::value::WithDimensions;
14use metrique_writer_core::value::{FlagConstructor, ForceFlag};
15
16use crate::{CloseValue, CloseValueRef, InflectableEntry};
17
18macro_rules! close_value_ref {
19 ($($type:ty),+) => {
20 $(
21 impl $crate::CloseValue for &'_ $type {
22 type Closed = $type;
23 fn close(self) -> Self::Closed {
24 *self
25 }
26 }
27 impl $crate::CloseValue for $type {
28 type Closed = $type;
29 fn close(self) -> Self::Closed {
30 self
31 }
32 }
33 )+
34 };
35}
36
37macro_rules! close_value {
38 ($($type:ty),+) => {
39 $(
40 impl $crate::CloseValue for $type {
41 type Closed = $type;
42 fn close(self) -> Self::Closed {
43 self
44 }
45 }
46 )+
47 };
48}
49
50close_value_ref!(
54 bool, Duration, f32, f64, u16, u32, u64, u8, usize, SystemTime
55);
56
57close_value!(String);
58
59#[diagnostic::do_not_recommend]
60impl<'a> CloseValue for &'a str {
61 type Closed = &'a str;
62
63 fn close(self) -> Self::Closed {
64 self
65 }
66}
67
68#[diagnostic::do_not_recommend]
69impl<'a> CloseValue for &&'a str {
70 type Closed = &'a str;
71
72 fn close(self) -> Self::Closed {
73 *self
74 }
75}
76
77#[diagnostic::do_not_recommend]
78impl CloseValue for &Arc<String> {
79 type Closed = Arc<String>;
80
81 fn close(self) -> Self::Closed {
82 self.clone()
83 }
84}
85
86impl CloseValue for Arc<String> {
87 type Closed = Arc<String>;
88
89 fn close(self) -> Self::Closed {
90 self
91 }
92}
93
94#[diagnostic::do_not_recommend]
95impl<'a, T: ToOwned + ?Sized> CloseValue for Cow<'a, T> {
96 type Closed = Cow<'a, T>;
97
98 fn close(self) -> Self::Closed {
99 self
100 }
101}
102
103#[diagnostic::do_not_recommend]
104impl<T, C> CloseValue for &'_ Arc<T>
105where
106 T: CloseValueRef<Closed = C>,
107{
108 type Closed = C;
109
110 fn close(self) -> Self::Closed {
111 T::close_ref(self)
112 }
113}
114
115#[diagnostic::do_not_recommend]
116impl<T, C> CloseValue for Arc<T>
117where
118 T: CloseValueRef<Closed = C>,
119{
120 type Closed = C;
121
122 fn close(self) -> Self::Closed {
123 T::close_ref(&self)
124 }
125}
126
127#[diagnostic::do_not_recommend]
128impl<T, C> CloseValue for &'_ std::sync::OnceLock<T>
129where
130 T: CloseValueRef<Closed = C>,
131{
132 type Closed = Option<C>;
133
134 fn close(self) -> Self::Closed {
135 self.get().map(T::close_ref)
136 }
137}
138
139#[diagnostic::do_not_recommend]
140impl<T: CloseValue> CloseValue for std::sync::OnceLock<T> {
141 type Closed = Option<T::Closed>;
142
143 fn close(self) -> Self::Closed {
144 self.into_inner().map(T::close)
145 }
146}
147
148#[diagnostic::do_not_recommend]
149impl<T, C> CloseValue for &'_ MutexGuard<'_, T>
150where
151 T: CloseValueRef<Closed = C>,
152{
153 type Closed = C;
154
155 fn close(self) -> Self::Closed {
156 T::close_ref(self)
157 }
158}
159
160#[diagnostic::do_not_recommend]
161impl<T, C> CloseValue for MutexGuard<'_, T>
162where
163 T: CloseValueRef<Closed = C>,
164{
165 type Closed = C;
166
167 fn close(self) -> Self::Closed {
168 T::close_ref(&self)
169 }
170}
171
172#[diagnostic::do_not_recommend]
173impl<T, C> CloseValue for Mutex<T>
174where
175 T: CloseValueRef<Closed = C>,
176{
177 type Closed = Option<C>;
178
179 fn close(self) -> Self::Closed {
180 self.close_ref()
181 }
182}
183
184#[diagnostic::do_not_recommend]
185impl<T, C> CloseValue for &'_ Mutex<T>
186where
187 T: CloseValueRef<Closed = C>,
188{
189 type Closed = Option<C>;
190
191 fn close(self) -> Self::Closed {
192 Some(self.lock().ok()?.close())
193 }
194}
195
196#[diagnostic::do_not_recommend]
197impl<T: CloseValue> CloseValue for Option<T> {
198 type Closed = Option<T::Closed>;
199
200 fn close(self) -> Self::Closed {
201 self.map(|v| v.close())
202 }
203}
204
205#[diagnostic::do_not_recommend]
206impl<T> CloseValue for &'_ Option<T>
207where
208 T: CloseValueRef,
209{
210 type Closed = Option<T::Closed>;
211
212 fn close(self) -> Self::Closed {
213 self.as_ref().map(|v| v.close_ref())
214 }
215}
216
217#[diagnostic::do_not_recommend]
218impl<V: CloseValue> CloseValue for Vec<V> {
219 type Closed = Vec<V::Closed>;
220
221 fn close(self) -> Self::Closed {
222 self.into_iter().map(CloseValue::close).collect()
223 }
224}
225
226#[diagnostic::do_not_recommend]
227impl<T: CloseValue, const N: usize> CloseValue for WithDimensions<T, N> {
228 type Closed = WithDimensions<T::Closed, N>;
229
230 fn close(self) -> Self::Closed {
231 self.map_value(|v| v.close())
232 }
233}
234
235#[diagnostic::do_not_recommend]
238impl<T: CloseValue, F: FlagConstructor> CloseValue for ForceFlag<T, F> {
239 type Closed = ForceFlag<T::Closed, F>;
240
241 fn close(self) -> Self::Closed {
242 self.map_value(|v| v.close())
243 }
244}
245
246struct ForceFlagEntryWriter<'a, W, FLAGS: FlagConstructor> {
247 writer: &'a mut W,
248 phantom: PhantomData<FLAGS>,
249}
250
251impl<'a, W: EntryWriter<'a>, FLAGS: FlagConstructor> EntryWriter<'a>
252 for ForceFlagEntryWriter<'_, W, FLAGS>
253{
254 fn timestamp(&mut self, timestamp: std::time::SystemTime) {
255 self.writer.timestamp(timestamp)
256 }
257
258 fn value(
259 &mut self,
260 name: impl Into<std::borrow::Cow<'a, str>>,
261 value: &(impl metrique_writer_core::Value + ?Sized),
262 ) {
263 self.writer.value(name, &ForceFlag::<_, FLAGS>::from(value))
264 }
265
266 fn config(&mut self, config: &'a dyn metrique_writer_core::EntryConfig) {
267 self.writer.config(config);
268 }
269}
270
271#[diagnostic::do_not_recommend]
272impl<T: CloseValueRef, F: FlagConstructor> CloseValue for &'_ ForceFlag<T, F> {
273 type Closed = ForceFlag<T::Closed, F>;
274
275 fn close(self) -> Self::Closed {
276 self.map_value_ref(|v| v.close_ref())
277 }
278}
279
280#[diagnostic::do_not_recommend]
281impl<NS: crate::NameStyle, T: InflectableEntry<NS>, F: FlagConstructor> InflectableEntry<NS>
282 for ForceFlag<T, F>
283{
284 fn write<'a>(&'a self, writer: &mut impl metrique_writer_core::EntryWriter<'a>) {
285 <T as InflectableEntry<NS>>::write(
286 self,
287 &mut ForceFlagEntryWriter {
288 writer,
289 phantom: PhantomData::<F>,
290 },
291 );
292 }
293}
294
295#[diagnostic::do_not_recommend]
296impl<NS: crate::NameStyle, T: InflectableEntry<NS>, const N: usize> InflectableEntry<NS>
297 for WithDimensions<T, N>
298{
299 fn write<'a>(&'a self, writer: &mut impl metrique_writer_core::EntryWriter<'a>) {
300 <T as InflectableEntry<NS>>::write(self, &mut self.entry_writer_wrapper(writer))
301 }
302}
303
304#[cfg(test)]
305mod tests {
306 use std::sync::{Arc, Mutex};
307
308 use crate::CloseValue;
309 use metrique_writer_core::value::WithDimensions;
310
311 #[derive(Clone, Debug)]
312 struct Closeable;
313 impl CloseValue for Closeable {
314 type Closed = usize;
315
316 fn close(self) -> Self::Closed {
317 42
318 }
319 }
320
321 impl CloseValue for &'_ Closeable {
322 type Closed = usize;
323
324 fn close(self) -> Self::Closed {
325 42
326 }
327 }
328
329 #[test]
330 fn close_option() {
331 let x = Some(Closeable);
332 assert_eq!(x.close(), Some(42));
333 }
334
335 #[test]
336 fn close_arc() {
337 let x = Arc::new(Closeable);
338 assert_eq!(x.close(), 42);
339 }
340
341 #[test]
342 fn close_arc_mutex() {
343 let x = Arc::new(Mutex::new(Closeable));
344 assert_eq!(x.close(), Some(42));
345 }
346
347 #[test]
348 fn close_arc_mutex_poisoned() {
349 let x = Arc::new(Mutex::new(Closeable));
350 let x_cloned = x.clone();
351 let _ = std::thread::spawn(move || {
352 let _guard = x_cloned.lock();
353 panic!();
354 })
355 .join();
356 assert_eq!(x.close(), None);
357 }
358
359 #[test]
360 fn close_with_dimensions() {
361 let v: WithDimensions<Closeable, 1> = WithDimensions::new(Closeable, "foo", "bar");
362 let closed = v.close();
363 assert_eq!(*closed, 42);
364 }
365
366 #[test]
367 fn close_once_lock_initialized() {
368 let lock = std::sync::OnceLock::new();
369 lock.set(Closeable).unwrap();
370 assert_eq!((&lock).close(), Some(42));
371 }
372
373 #[test]
374 fn close_once_lock_uninitialized() {
375 let lock = std::sync::OnceLock::<Closeable>::new();
376 assert_eq!((&lock).close(), None);
377 }
378}