s2n_quic_core/event/metrics/aggregate/
info.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use super::Units;
5use crate::probe;
6use core::{ffi::CStr, fmt, ops};
7
8#[derive(Copy, Clone, Debug)]
9#[non_exhaustive]
10pub struct Info {
11    pub id: usize,
12    pub name: &'static Str,
13    pub units: Units,
14}
15
16#[doc(hidden)]
17pub struct Builder {
18    pub id: usize,
19    pub name: &'static Str,
20    pub units: Units,
21}
22
23impl Builder {
24    #[inline]
25    pub const fn build(self) -> Info {
26        Info {
27            id: self.id,
28            name: self.name,
29            units: self.units,
30        }
31    }
32}
33
34#[derive(Copy, Clone, Debug)]
35#[non_exhaustive]
36pub struct Variant {
37    pub id: usize,
38    pub name: &'static Str,
39}
40
41#[doc(hidden)]
42pub mod variant {
43    use super::*;
44
45    pub struct Builder {
46        pub id: usize,
47        pub name: &'static Str,
48    }
49
50    impl Builder {
51        pub const fn build(self) -> Variant {
52            Variant {
53                id: self.id,
54                name: self.name,
55            }
56        }
57    }
58}
59
60/// A str that is also a [`CStr`]
61#[repr(transparent)]
62pub struct Str(str);
63
64impl Str {
65    /// Creates a new `Str` value
66    ///
67    /// # Panics
68    ///
69    /// The provided slice **must** be nul-terminated and not contain any interior
70    /// nul bytes.
71    pub const fn new(value: &str) -> &Self {
72        {
73            let value = value.as_bytes();
74
75            if value.is_empty() {
76                panic!("provided string is empty");
77            }
78
79            let last_idx = value.len() - 1;
80
81            if value[last_idx] != 0 {
82                panic!("string does not end in nul byte");
83            }
84
85            let mut idx = 0;
86            while idx < last_idx {
87                if value[idx] == 0 {
88                    panic!("string contains nul byte");
89                }
90                idx += 1;
91            }
92        }
93
94        unsafe { Self::new_unchecked(value) }
95    }
96
97    /// # Safety
98    ///
99    /// The provided slice **must** be nul-terminated and not contain any interior
100    /// nul bytes.
101    pub const unsafe fn new_unchecked(value: &str) -> &Self {
102        unsafe {
103            // SAFETY: `Self` is `repr(transparent) over a `str``
104            core::mem::transmute::<&str, &Self>(value)
105        }
106    }
107}
108
109impl fmt::Debug for Str {
110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111        (**self).fmt(f)
112    }
113}
114
115impl fmt::Display for Str {
116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117        (**self).fmt(f)
118    }
119}
120
121impl ops::Deref for Str {
122    type Target = str;
123
124    #[inline]
125    fn deref(&self) -> &Self::Target {
126        unsafe {
127            // SAFETY: string was already checked to contain at least one byte
128            assume!(!self.0.is_empty());
129        }
130        let len = self.0.len() - 1;
131        &self.0[..len]
132    }
133}
134
135impl AsRef<str> for Str {
136    #[inline]
137    fn as_ref(&self) -> &str {
138        self
139    }
140}
141
142impl AsRef<CStr> for Str {
143    #[inline]
144    fn as_ref(&self) -> &CStr {
145        unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes()) }
146    }
147}
148
149impl probe::Arg for &Str {
150    #[inline]
151    fn into_usdt(self) -> isize {
152        self.0.as_ptr() as _
153    }
154}