use core::time::Duration;
use std::marker::PhantomData;
use std::sync::{Arc, MutexGuard};
use std::time::SystemTime;
use std::{borrow::Cow, sync::Mutex};
use metrique_writer_core::EntryWriter;
use metrique_writer_core::value::WithDimensions;
use metrique_writer_core::value::{FlagConstructor, ForceFlag};
use crate::{CloseValue, CloseValueRef, InflectableEntry};
macro_rules! close_value_ref {
($($type:ty),+) => {
$(
impl $crate::CloseValue for &'_ $type {
type Closed = $type;
fn close(self) -> Self::Closed {
*self
}
}
impl $crate::CloseValue for $type {
type Closed = $type;
fn close(self) -> Self::Closed {
self
}
}
)+
};
}
macro_rules! close_value {
($($type:ty),+) => {
$(
impl $crate::CloseValue for $type {
type Closed = $type;
fn close(self) -> Self::Closed {
self
}
}
)+
};
}
close_value_ref!(
bool, Duration, f32, f64, u16, u32, u64, u8, usize, SystemTime
);
close_value!(String);
#[diagnostic::do_not_recommend]
impl<'a> CloseValue for &'a str {
type Closed = &'a str;
fn close(self) -> Self::Closed {
self
}
}
#[diagnostic::do_not_recommend]
impl<'a> CloseValue for &&'a str {
type Closed = &'a str;
fn close(self) -> Self::Closed {
*self
}
}
#[diagnostic::do_not_recommend]
impl CloseValue for &Arc<String> {
type Closed = Arc<String>;
fn close(self) -> Self::Closed {
self.clone()
}
}
impl CloseValue for Arc<String> {
type Closed = Arc<String>;
fn close(self) -> Self::Closed {
self
}
}
#[diagnostic::do_not_recommend]
impl<'a, T: ToOwned + ?Sized> CloseValue for Cow<'a, T> {
type Closed = Cow<'a, T>;
fn close(self) -> Self::Closed {
self
}
}
#[diagnostic::do_not_recommend]
impl<T, C> CloseValue for &'_ Arc<T>
where
T: CloseValueRef<Closed = C>,
{
type Closed = C;
fn close(self) -> Self::Closed {
T::close_ref(self)
}
}
#[diagnostic::do_not_recommend]
impl<T, C> CloseValue for Arc<T>
where
T: CloseValueRef<Closed = C>,
{
type Closed = C;
fn close(self) -> Self::Closed {
T::close_ref(&self)
}
}
#[diagnostic::do_not_recommend]
impl<T, C> CloseValue for &'_ std::sync::OnceLock<T>
where
T: CloseValueRef<Closed = C>,
{
type Closed = Option<C>;
fn close(self) -> Self::Closed {
self.get().map(T::close_ref)
}
}
#[diagnostic::do_not_recommend]
impl<T: CloseValue> CloseValue for std::sync::OnceLock<T> {
type Closed = Option<T::Closed>;
fn close(self) -> Self::Closed {
self.into_inner().map(T::close)
}
}
#[diagnostic::do_not_recommend]
impl<T, C> CloseValue for &'_ MutexGuard<'_, T>
where
T: CloseValueRef<Closed = C>,
{
type Closed = C;
fn close(self) -> Self::Closed {
T::close_ref(self)
}
}
#[diagnostic::do_not_recommend]
impl<T, C> CloseValue for MutexGuard<'_, T>
where
T: CloseValueRef<Closed = C>,
{
type Closed = C;
fn close(self) -> Self::Closed {
T::close_ref(&self)
}
}
#[diagnostic::do_not_recommend]
impl<T, C> CloseValue for Mutex<T>
where
T: CloseValueRef<Closed = C>,
{
type Closed = Option<C>;
fn close(self) -> Self::Closed {
self.close_ref()
}
}
#[diagnostic::do_not_recommend]
impl<T, C> CloseValue for &'_ Mutex<T>
where
T: CloseValueRef<Closed = C>,
{
type Closed = Option<C>;
fn close(self) -> Self::Closed {
Some(self.lock().ok()?.close())
}
}
#[diagnostic::do_not_recommend]
impl<T: CloseValue> CloseValue for Option<T> {
type Closed = Option<T::Closed>;
fn close(self) -> Self::Closed {
self.map(|v| v.close())
}
}
#[diagnostic::do_not_recommend]
impl<T> CloseValue for &'_ Option<T>
where
T: CloseValueRef,
{
type Closed = Option<T::Closed>;
fn close(self) -> Self::Closed {
self.as_ref().map(|v| v.close_ref())
}
}
#[diagnostic::do_not_recommend]
impl<T: CloseValue, const N: usize> CloseValue for WithDimensions<T, N> {
type Closed = WithDimensions<T::Closed, N>;
fn close(self) -> Self::Closed {
self.map_value(|v| v.close())
}
}
#[diagnostic::do_not_recommend]
impl<T: CloseValue, F: FlagConstructor> CloseValue for ForceFlag<T, F> {
type Closed = ForceFlag<T::Closed, F>;
fn close(self) -> Self::Closed {
self.map_value(|v| v.close())
}
}
struct ForceFlagEntryWriter<'a, W, FLAGS: FlagConstructor> {
writer: &'a mut W,
phantom: PhantomData<FLAGS>,
}
impl<'a, W: EntryWriter<'a>, FLAGS: FlagConstructor> EntryWriter<'a>
for ForceFlagEntryWriter<'_, W, FLAGS>
{
fn timestamp(&mut self, timestamp: std::time::SystemTime) {
self.writer.timestamp(timestamp)
}
fn value(
&mut self,
name: impl Into<std::borrow::Cow<'a, str>>,
value: &(impl metrique_writer_core::Value + ?Sized),
) {
self.writer.value(name, &ForceFlag::<_, FLAGS>::from(value))
}
fn config(&mut self, config: &'a dyn metrique_writer_core::EntryConfig) {
self.writer.config(config);
}
}
#[diagnostic::do_not_recommend]
impl<T: CloseValueRef, F: FlagConstructor> CloseValue for &'_ ForceFlag<T, F> {
type Closed = ForceFlag<T::Closed, F>;
fn close(self) -> Self::Closed {
self.map_value_ref(|v| v.close_ref())
}
}
#[diagnostic::do_not_recommend]
impl<NS: crate::NameStyle, T: InflectableEntry<NS>, F: FlagConstructor> InflectableEntry<NS>
for ForceFlag<T, F>
{
fn write<'a>(&'a self, writer: &mut impl metrique_writer_core::EntryWriter<'a>) {
<T as InflectableEntry<NS>>::write(
self,
&mut ForceFlagEntryWriter {
writer,
phantom: PhantomData::<F>,
},
);
}
}
#[diagnostic::do_not_recommend]
impl<NS: crate::NameStyle, T: InflectableEntry<NS>, const N: usize> InflectableEntry<NS>
for WithDimensions<T, N>
{
fn write<'a>(&'a self, writer: &mut impl metrique_writer_core::EntryWriter<'a>) {
<T as InflectableEntry<NS>>::write(self, &mut self.entry_writer_wrapper(writer))
}
}
#[cfg(test)]
mod tests {
use std::sync::{Arc, Mutex};
use crate::CloseValue;
use metrique_writer_core::value::WithDimensions;
#[derive(Clone, Debug)]
struct Closeable;
impl CloseValue for Closeable {
type Closed = usize;
fn close(self) -> Self::Closed {
42
}
}
impl CloseValue for &'_ Closeable {
type Closed = usize;
fn close(self) -> Self::Closed {
42
}
}
#[test]
fn close_option() {
let x = Some(Closeable);
assert_eq!(x.close(), Some(42));
}
#[test]
fn close_arc() {
let x = Arc::new(Closeable);
assert_eq!(x.close(), 42);
}
#[test]
fn close_arc_mutex() {
let x = Arc::new(Mutex::new(Closeable));
assert_eq!(x.close(), Some(42));
}
#[test]
fn close_arc_mutex_poisoned() {
let x = Arc::new(Mutex::new(Closeable));
let x_cloned = x.clone();
let _ = std::thread::spawn(move || {
let _guard = x_cloned.lock();
panic!();
})
.join();
assert_eq!(x.close(), None);
}
#[test]
fn close_with_dimensions() {
let v: WithDimensions<Closeable, 1> = WithDimensions::new(Closeable, "foo", "bar");
let closed = v.close();
assert_eq!(*closed, 42);
}
#[test]
fn close_once_lock_initialized() {
let lock = std::sync::OnceLock::new();
lock.set(Closeable).unwrap();
assert_eq!((&lock).close(), Some(42));
}
#[test]
fn close_once_lock_uninitialized() {
let lock = std::sync::OnceLock::<Closeable>::new();
assert_eq!((&lock).close(), None);
}
}