Skip to main content

metrique_core/
close_value_impls.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! All default implementations of CloseValue, grouped for clarity
5
6use 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
50// We have all of these manual impls to avoid the coherence issues we would have from having a blanket impl.
51// This allows us to have specific impls for things like `WithDimensions`
52
53close_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// no by-ref impl for WithDimensions due to not wanting to implicitly clone the dimensions
236
237#[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}