1use std::borrow::Cow;
2use std::sync::Arc;
3
4use opentelemetry::{Array, StringValue, Value};
5
6#[doc(hidden)]
14pub struct SpecializeValue<T>(Option<T>);
15
16impl<T> SpecializeValue<T> {
17 pub fn new(value: T) -> Self {
18 Self(Some(value))
19 }
20
21 #[inline]
22 fn take(&mut self) -> T {
23 self.0.take().expect("value is not Some")
24 }
25}
26
27#[doc(hidden)]
28pub trait Specialization: private::Sealed {
29 fn take_value(&mut self) -> Option<Value>;
30}
31
32#[doc(hidden)]
33mod private {
34 use super::SpecializeValue;
35
36 pub trait Sealed {}
37
38 impl<T: Sealed> Sealed for &mut T {}
39 impl<T> Sealed for SpecializeValue<T> {}
40}
41
42macro_rules! sealed {
43 ($($t:ty),*) => {
44 $(impl private::Sealed for $t {})*
45 };
46}
47
48macro_rules! integer_specialization {
49 ($type:ty) => {
50 impl Specialization for Option<$type> {
51 #[inline]
52 fn take_value(&mut self) -> Option<Value> {
53 Some(Value::I64(self.take()? as i64))
54 }
55 }
56
57 sealed!(Option<$type>);
58 };
59}
60
61integer_specialization!(i32);
62integer_specialization!(i64);
63integer_specialization!(u32);
64integer_specialization!(i16);
65integer_specialization!(u16);
66integer_specialization!(i8);
67integer_specialization!(u8);
68
69impl Specialization for Option<f32> {
70 #[inline]
71 fn take_value(&mut self) -> Option<Value> {
72 Some(Value::F64(self.take()? as f64))
73 }
74}
75
76sealed!(Option<f32>);
77
78impl Specialization for Option<f64> {
79 #[inline]
80 fn take_value(&mut self) -> Option<Value> {
81 Some(Value::F64(self.take()?))
82 }
83}
84
85sealed!(Option<f64>);
86
87impl Specialization for Option<bool> {
88 #[inline]
89 fn take_value(&mut self) -> Option<Value> {
90 Some(Value::Bool(self.take()?))
91 }
92}
93
94sealed!(Option<bool>);
95
96impl Specialization for Option<&'static str> {
97 #[inline]
98 fn take_value(&mut self) -> Option<Value> {
99 Some(Value::String(self.take()?.into()))
100 }
101}
102
103sealed!(Option<&'static str>);
104
105impl Specialization for Option<StringValue> {
106 #[inline]
107 fn take_value(&mut self) -> Option<Value> {
108 Some(Value::String(self.take()?))
109 }
110}
111
112sealed!(Option<StringValue>);
113
114impl Specialization for Option<String> {
115 #[inline]
116 fn take_value(&mut self) -> Option<Value> {
117 Some(Value::String(self.take()?.into()))
118 }
119}
120
121sealed!(Option<String>);
122
123impl Specialization for Option<Arc<str>> {
124 #[inline]
125 fn take_value(&mut self) -> Option<Value> {
126 Some(Value::String(self.take()?.into()))
127 }
128}
129
130sealed!(Option<Arc<str>>);
131
132impl Specialization for Option<Cow<'static, str>> {
133 #[inline]
134 fn take_value(&mut self) -> Option<Value> {
135 Some(Value::String(self.take()?.into()))
136 }
137}
138
139sealed!(Option<Cow<'static, str>>);
140
141impl Specialization for Option<Value> {
142 #[inline]
143 fn take_value(&mut self) -> Option<Value> {
144 self.take()
145 }
146}
147
148sealed!(Option<Value>);
149
150impl Specialization for Option<Array> {
151 #[inline]
152 fn take_value(&mut self) -> Option<Value> {
153 Some(Value::Array(self.take()?))
154 }
155}
156
157sealed!(Option<Array>);
158
159impl Specialization for Option<Vec<bool>> {
160 #[inline]
161 fn take_value(&mut self) -> Option<Value> {
162 Some(Value::Array(Array::Bool(self.take()?)))
163 }
164}
165
166sealed!(Option<Vec<bool>>);
167
168macro_rules! integer_vector_specialization {
169 ($type:ty) => {
170 impl Specialization for Option<Vec<$type>> {
171 #[inline]
172 fn take_value(&mut self) -> Option<Value> {
173 Some(Value::Array(Array::I64(
174 self.take()?.into_iter().map(|i| i as i64).collect(),
175 )))
176 }
177 }
178
179 sealed!(Option<Vec<$type>>);
180 };
181}
182
183integer_vector_specialization!(i32);
184integer_vector_specialization!(i64);
185integer_vector_specialization!(u32);
186integer_vector_specialization!(i16);
187integer_vector_specialization!(u16);
188integer_vector_specialization!(i8);
189integer_vector_specialization!(u8);
190
191impl Specialization for Option<Vec<f64>> {
192 #[inline]
193 fn take_value(&mut self) -> Option<Value> {
194 Some(Value::Array(Array::F64(self.take()?)))
195 }
196}
197
198sealed!(Option<Vec<f64>>);
199
200impl Specialization for Option<Vec<f32>> {
201 #[inline]
202 fn take_value(&mut self) -> Option<Value> {
203 Some(Value::Array(Array::F64(self.take()?.into_iter().map(|f| f as f64).collect())))
204 }
205}
206
207sealed!(Option<Vec<f32>>);
208
209impl Specialization for Option<Vec<&'static str>> {
210 #[inline]
211 fn take_value(&mut self) -> Option<Value> {
212 Some(Value::Array(Array::String(
213 self.take()?.into_iter().map(|s| s.into()).collect(),
214 )))
215 }
216}
217
218sealed!(Option<Vec<&'static str>>);
219
220impl Specialization for Option<Vec<StringValue>> {
221 #[inline]
222 fn take_value(&mut self) -> Option<Value> {
223 Some(Value::Array(Array::String(self.take()?)))
224 }
225}
226
227sealed!(Option<Vec<StringValue>>);
228
229impl Specialization for Option<Vec<String>> {
230 #[inline]
231 fn take_value(&mut self) -> Option<Value> {
232 Some(Value::Array(Array::String(
233 self.take()?.into_iter().map(|s| s.into()).collect(),
234 )))
235 }
236}
237
238sealed!(Option<Vec<String>>);
239
240impl Specialization for Option<Vec<Arc<str>>> {
241 #[inline]
242 fn take_value(&mut self) -> Option<Value> {
243 Some(Value::Array(Array::String(
244 self.take()?.into_iter().map(|s| s.into()).collect(),
245 )))
246 }
247}
248
249sealed!(Option<Vec<Arc<str>>>);
250
251impl Specialization for Option<Vec<Cow<'static, str>>> {
252 #[inline]
253 fn take_value(&mut self) -> Option<Value> {
254 Some(Value::Array(Array::String(
255 self.take()?.into_iter().map(|s| s.into()).collect(),
256 )))
257 }
258}
259
260sealed!(Option<Vec<Cow<'static, str>>>);
261
262impl<T: std::fmt::Display> Specialization for &mut &mut SpecializeValue<T> {
263 #[inline]
264 fn take_value(&mut self) -> Option<Value> {
265 Some(Value::String(self.take().to_string().into()))
266 }
267}
268
269impl<T: Into<Value>> Specialization for &mut &mut &mut SpecializeValue<T> {
270 #[inline]
271 fn take_value(&mut self) -> Option<Value> {
272 Some(self.take().into())
273 }
274}
275
276impl<T> Specialization for &mut &mut &mut &mut SpecializeValue<T>
277where
278 T: Specialization,
279{
280 #[inline]
281 fn take_value(&mut self) -> Option<Value> {
282 self.take().take_value()
283 }
284}
285
286impl<T> Specialization for &mut &mut &mut &mut &mut SpecializeValue<T>
287where
288 Option<T>: Specialization,
289{
290 #[inline]
291 fn take_value(&mut self) -> Option<Value> {
292 Some(self.take()).take_value()
293 }
294}
295
296#[doc(hidden)]
297#[macro_export]
298macro_rules! to_value {
299 ($value:expr) => {{
300 use $crate::value::Specialization;
301 (&mut &mut &mut &mut &mut &mut $crate::value::SpecializeValue::new($value)).take_value()
302 }};
303}
304
305#[cfg(test)]
306#[cfg_attr(all(test, coverage_nightly), coverage(off))]
307mod tests {
308 use super::*;
309
310 #[test]
311 fn test_specialization_i64() {
312 let value = to_value!(1);
313 assert_eq!(value, Some(Value::I64(1)));
314 }
315
316 #[test]
317 fn test_specialization_display() {
318 struct Displayable(i64);
319 impl std::fmt::Display for Displayable {
320 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
321 write!(f, "{}", self.0)
322 }
323 }
324 let value = to_value!(Displayable(1));
325 assert_eq!(value, Some(Value::String("1".into())));
326 }
327
328 #[test]
329 fn test_specialization_into() {
330 struct Intoable(i64);
331 impl From<Intoable> for Value {
332 fn from(val: Intoable) -> Self {
333 Value::I64(val.0)
334 }
335 }
336 let value = to_value!(Intoable(1));
337 assert_eq!(value, Some(Value::I64(1)));
338 }
339
340 #[test]
341 fn test_specialization_array() {
342 let value = to_value!(vec![1, 2, 3]);
343 assert_eq!(value, Some(Value::Array(Array::I64(vec![1, 2, 3]))));
344 }
345
346 #[test]
347 fn test_specialization_integer_vector_option() {
348 let value = to_value!(Some(vec![1, 2, 3]));
349 assert_eq!(value, Some(Value::Array(Array::I64(vec![1, 2, 3]))));
350 }
351
352 #[test]
353 fn test_specialization_integer_vector_none() {
354 let value = to_value!(None::<Vec<i32>>);
355 assert_eq!(value, None);
356 }
357
358 #[test]
359 fn test_specialization_f64_vector() {
360 let value = to_value!(vec![1.0, 2.0, 3.0]);
361 assert_eq!(value, Some(Value::Array(Array::F64(vec![1.0, 2.0, 3.0]))));
362 }
363
364 #[test]
365 fn test_specialization_f32_vector() {
366 let value = to_value!(vec![1.0f32, 2.0f32, 3.0f32]);
367 assert_eq!(value, Some(Value::Array(Array::F64(vec![1.0, 2.0, 3.0]))));
368 }
369
370 #[test]
371 fn test_none_str() {
372 let value = to_value!(None::<&'static str>);
373 assert_eq!(value, None);
374 }
375
376 #[test]
377 fn test_some_str() {
378 let value = to_value!("hello");
379 assert_eq!(value, Some(Value::String("hello".into())));
380 }
381
382 #[test]
383 fn test_specialization_i32() {
384 let value = to_value!(1i32);
385 assert_eq!(value, Some(Value::I64(1)));
386 }
387
388 #[test]
389 fn test_specialization_u32() {
390 let value = to_value!(1u32);
391 assert_eq!(value, Some(Value::I64(1)));
392 }
393
394 #[test]
395 fn test_specialization_i16() {
396 let value = to_value!(1i16);
397 assert_eq!(value, Some(Value::I64(1)));
398 }
399
400 #[test]
401 fn test_specialization_u16() {
402 let value = to_value!(1u16);
403 assert_eq!(value, Some(Value::I64(1)));
404 }
405
406 #[test]
407 fn test_specialization_i8() {
408 let value = to_value!(1i8);
409 assert_eq!(value, Some(Value::I64(1)));
410 }
411
412 #[test]
413 fn test_specialization_u8() {
414 let value = to_value!(1u8);
415 assert_eq!(value, Some(Value::I64(1)));
416 }
417
418 #[test]
419 fn test_specialization_f32() {
420 let value = to_value!(1.0f32);
421 assert_eq!(value, Some(Value::F64(1.0)));
422 }
423
424 #[test]
425 fn test_specialization_bool() {
426 let value = to_value!(true);
427 assert_eq!(value, Some(Value::Bool(true)));
428 }
429
430 #[test]
431 fn test_specialization_string() {
432 let value = to_value!("hello".to_string());
433 assert_eq!(value, Some(Value::String("hello".into())));
434 }
435
436 #[test]
437 fn test_specialization_arc_str() {
438 let arc_str = Arc::from("hello");
439 let value = to_value!(arc_str);
440 assert_eq!(value, Some(Value::String("hello".into())));
441 }
442
443 #[test]
444 fn test_specialization_cow_str() {
445 let cow_str: Cow<'static, str> = Cow::Borrowed("hello");
446 let value = to_value!(cow_str);
447 assert_eq!(value, Some(Value::String("hello".into())));
448 }
449
450 #[test]
451 fn test_specialization_value() {
452 let val = Value::I64(42);
453 let value = to_value!(val);
454 assert_eq!(value, Some(Value::I64(42)));
455 }
456
457 #[test]
458 fn test_specialization_array_direct() {
459 let arr = Array::I64(vec![1, 2, 3]);
460 let value = to_value!(arr);
461 assert_eq!(value, Some(Value::Array(Array::I64(vec![1, 2, 3]))));
462 }
463
464 #[test]
465 fn test_specialization_vec_bool() {
466 let vec = vec![true, false, true];
467 let value = to_value!(vec);
468 assert_eq!(value, Some(Value::Array(Array::Bool(vec![true, false, true]))));
469 }
470
471 #[test]
472 fn test_specialization_vec_str() {
473 let vec = vec!["a", "b", "c"];
474 let value = to_value!(vec);
475 assert_eq!(
476 value,
477 Some(Value::Array(Array::String(vec!["a".into(), "b".into(), "c".into()])))
478 );
479 }
480
481 #[test]
482 fn test_specialization_vec_string() {
483 let vec = vec!["a".to_string(), "b".to_string(), "c".to_string()];
484 let value = to_value!(vec);
485 assert_eq!(
486 value,
487 Some(Value::Array(Array::String(vec!["a".into(), "b".into(), "c".into()])))
488 );
489 }
490
491 #[test]
492 fn test_specialization_vec_arc_str() {
493 let vec = vec![Arc::from("a"), Arc::from("b"), Arc::from("c")];
494 let value = to_value!(vec);
495 assert_eq!(
496 value,
497 Some(Value::Array(Array::String(vec!["a".into(), "b".into(), "c".into()])))
498 );
499 }
500
501 #[test]
502 fn test_specialization_vec_cow_str() {
503 let vec = vec![Cow::Borrowed("a"), Cow::Borrowed("b"), Cow::Borrowed("c")];
504 let value = to_value!(vec);
505 assert_eq!(
506 value,
507 Some(Value::Array(Array::String(vec!["a".into(), "b".into(), "c".into()])))
508 );
509 }
510
511 #[test]
512 fn test_specialization_option_i32_some() {
513 let value = to_value!(Some(1i32));
514 assert_eq!(value, Some(Value::I64(1)));
515 }
516
517 #[test]
518 fn test_specialization_option_i32_none() {
519 let value = to_value!(None::<i32>);
520 assert_eq!(value, None);
521 }
522
523 #[test]
524 fn test_specialization_option_f64_some() {
525 let value = to_value!(Some(1.0f64));
526 assert_eq!(value, Some(Value::F64(1.0)));
527 }
528
529 #[test]
530 fn test_specialization_option_f63_none() {
531 let value = to_value!(None::<f64>);
532 assert_eq!(value, None);
533 }
534
535 #[test]
536 fn test_specialization_option_string_some() {
537 let value = to_value!(Some("hello".to_string()));
538 assert_eq!(value, Some(Value::String("hello".into())));
539 }
540
541 #[test]
542 fn test_specialization_option_string_none() {
543 let value = to_value!(None::<String>);
544 assert_eq!(value, None);
545 }
546
547 #[test]
548 fn test_specialization_option_string_value_some() {
549 let value = to_value!(Some(StringValue::from("hello")));
550 assert_eq!(value, Some(Value::String("hello".into())));
551 }
552
553 #[test]
554 fn test_specialization_option_string_value_none() {
555 let value = to_value!(None::<StringValue>);
556 assert_eq!(value, None);
557 }
558
559 #[test]
560 fn test_specialization_option_vec_string_value_some() {
561 let value = to_value!(Some(vec![StringValue::from("a"), StringValue::from("b")]));
562 assert_eq!(value, Some(Value::Array(Array::String(vec!["a".into(), "b".into()]))));
563 }
564
565 #[test]
566 fn test_specialization_option_vec_string_value_none() {
567 let value = to_value!(None::<Vec<StringValue>>);
568 assert_eq!(value, None);
569 }
570}