opentelemetry_spanprocessor_any/metrics/
number.rs1use std::cmp;
2use std::fmt;
3use std::sync::atomic::{AtomicU64, Ordering};
4
5#[derive(Clone, Debug, Default)]
9pub struct Number(u64);
10
11impl Number {
12 pub fn to_atomic(&self) -> AtomicNumber {
14 AtomicNumber(AtomicU64::new(self.0))
15 }
16
17 pub fn partial_cmp(&self, number_kind: &NumberKind, other: &Number) -> Option<cmp::Ordering> {
19 match number_kind {
20 NumberKind::I64 => (self.0 as i64).partial_cmp(&(other.0 as i64)),
21 NumberKind::F64 => {
22 let current = u64_to_f64(self.0);
23 let other = u64_to_f64(other.0);
24 current.partial_cmp(&other)
25 }
26 NumberKind::U64 => self.0.partial_cmp(&other.0),
27 }
28 }
29
30 pub fn to_i64(&self, number_kind: &NumberKind) -> i64 {
32 match number_kind {
33 NumberKind::F64 => u64_to_f64(self.0) as i64,
34 NumberKind::U64 | NumberKind::I64 => self.0 as i64,
35 }
36 }
37
38 pub fn to_f64(&self, number_kind: &NumberKind) -> f64 {
40 match number_kind {
41 NumberKind::I64 => (self.0 as i64) as f64,
42 NumberKind::F64 => u64_to_f64(self.0),
43 NumberKind::U64 => self.0 as f64,
44 }
45 }
46
47 pub fn to_u64(&self, number_kind: &NumberKind) -> u64 {
49 match number_kind {
50 NumberKind::F64 => u64_to_f64(self.0) as u64,
51 NumberKind::U64 | NumberKind::I64 => self.0,
52 }
53 }
54
55 pub fn is_nan(&self) -> bool {
57 u64_to_f64(self.0).is_nan()
58 }
59
60 pub fn is_negative(&self, number_kind: &NumberKind) -> bool {
62 match number_kind {
63 NumberKind::I64 => (self.0 as i64).is_negative(),
64 NumberKind::F64 => u64_to_f64(self.0).is_sign_negative(),
65 NumberKind::U64 => false,
66 }
67 }
68
69 pub fn to_debug(&self, kind: &NumberKind) -> Box<dyn fmt::Debug> {
71 match kind {
72 NumberKind::I64 => Box::new(self.0 as i64),
73 NumberKind::F64 => Box::new(u64_to_f64(self.0)),
74 NumberKind::U64 => Box::new(self.0),
75 }
76 }
77}
78
79#[derive(Debug, Default)]
81pub struct AtomicNumber(AtomicU64);
82
83impl AtomicNumber {
84 pub fn store(&self, val: &Number) {
86 self.0.store(val.0, Ordering::Relaxed)
87 }
88
89 pub fn fetch_add(&self, number_kind: &NumberKind, val: &Number) {
94 match number_kind {
95 NumberKind::I64 => {
96 let mut old = self.0.load(Ordering::Acquire);
97 loop {
98 let new = (old as i64).wrapping_add(val.0 as i64) as u64;
99 match self.0.compare_exchange_weak(
100 old,
101 new,
102 Ordering::AcqRel,
103 Ordering::Acquire,
104 ) {
105 Ok(_) => break,
106 Err(x) => old = x,
107 };
108 }
109 }
110 NumberKind::F64 => {
111 let mut old = self.0.load(Ordering::Acquire);
112 loop {
113 let new = u64_to_f64(old) + u64_to_f64(val.0);
114 match self.0.compare_exchange_weak(
115 old,
116 f64_to_u64(new),
117 Ordering::AcqRel,
118 Ordering::Acquire,
119 ) {
120 Ok(_) => break,
121 Err(x) => old = x,
122 };
123 }
124 }
125 NumberKind::U64 => {
126 self.0.fetch_add(val.0, Ordering::AcqRel);
127 }
128 }
129 }
130
131 pub fn fetch_sub(&self, number_kind: &NumberKind, val: &Number) {
136 match number_kind {
137 NumberKind::I64 => {
138 let mut old = self.0.load(Ordering::Acquire);
139 loop {
140 let new = (old as i64).wrapping_sub(val.0 as i64) as u64;
141 match self.0.compare_exchange_weak(
142 old,
143 new,
144 Ordering::AcqRel,
145 Ordering::Relaxed,
146 ) {
147 Ok(_) => break,
148 Err(x) => old = x,
149 };
150 }
151 }
152 NumberKind::F64 => {
153 let mut old = self.0.load(Ordering::Acquire);
154 loop {
155 let new = u64_to_f64(old) - u64_to_f64(val.0);
156 match self.0.compare_exchange_weak(
157 old,
158 f64_to_u64(new),
159 Ordering::AcqRel,
160 Ordering::Acquire,
161 ) {
162 Ok(_) => break,
163 Err(x) => old = x,
164 };
165 }
166 }
167 NumberKind::U64 => {
168 self.0.fetch_sub(val.0, Ordering::AcqRel);
169 }
170 }
171 }
172
173 pub fn load(&self) -> Number {
175 Number(self.0.load(Ordering::Relaxed))
176 }
177}
178
179impl Clone for AtomicNumber {
180 fn clone(&self) -> Self {
181 AtomicNumber(AtomicU64::new(self.0.load(Ordering::Relaxed)))
182 }
183}
184
185impl From<f64> for Number {
186 fn from(f: f64) -> Self {
187 Number(f64_to_u64(f))
188 }
189}
190
191impl From<i64> for Number {
192 fn from(i: i64) -> Self {
193 Number(i as u64)
194 }
195}
196
197impl From<u64> for Number {
198 fn from(u: u64) -> Self {
199 Number(u)
200 }
201}
202
203#[derive(Clone, Debug, PartialEq, Hash)]
205pub enum NumberKind {
206 I64,
208 F64,
210 U64,
212}
213
214impl NumberKind {
215 pub fn zero(&self) -> Number {
217 match self {
218 NumberKind::I64 => 0i64.into(),
219 NumberKind::F64 => 0f64.into(),
220 NumberKind::U64 => 0u64.into(),
221 }
222 }
223
224 pub fn max(&self) -> Number {
226 match self {
227 NumberKind::I64 => std::i64::MAX.into(),
228 NumberKind::F64 => std::f64::MAX.into(),
229 NumberKind::U64 => std::u64::MAX.into(),
230 }
231 }
232
233 pub fn min(&self) -> Number {
235 match self {
236 NumberKind::I64 => std::i64::MIN.into(),
237 NumberKind::F64 => std::f64::MIN.into(),
238 NumberKind::U64 => std::u64::MIN.into(),
239 }
240 }
241}
242
243#[inline]
244fn u64_to_f64(val: u64) -> f64 {
245 f64::from_bits(val)
246}
247
248#[inline]
249fn f64_to_u64(val: f64) -> u64 {
250 f64::to_bits(val)
251}