1use std::borrow::{Borrow, Cow};
2use std::sync::Arc;
3use std::{fmt, hash};
4
5#[non_exhaustive]
11#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
12pub struct Key(OtelString);
13
14impl Key {
15 pub fn new(value: impl Into<Key>) -> Self {
28 value.into()
29 }
30
31 pub const fn from_static_str(value: &'static str) -> Self {
33 Key(OtelString::Static(value))
34 }
35
36 pub fn as_str(&self) -> &str {
38 self.0.as_str()
39 }
40}
41
42impl From<&'static str> for Key {
43 fn from(key_str: &'static str) -> Self {
45 Key(OtelString::Static(key_str))
46 }
47}
48
49impl From<String> for Key {
50 fn from(string: String) -> Self {
52 Key(OtelString::Owned(string.into_boxed_str()))
53 }
54}
55
56impl From<Arc<str>> for Key {
57 fn from(string: Arc<str>) -> Self {
59 Key(OtelString::RefCounted(string))
60 }
61}
62
63impl From<Cow<'static, str>> for Key {
64 fn from(string: Cow<'static, str>) -> Self {
66 match string {
67 Cow::Borrowed(s) => Key(OtelString::Static(s)),
68 Cow::Owned(s) => Key(OtelString::Owned(s.into_boxed_str())),
69 }
70 }
71}
72
73impl fmt::Debug for Key {
74 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
75 self.0.fmt(fmt)
76 }
77}
78
79impl From<Key> for String {
80 fn from(key: Key) -> Self {
81 match key.0 {
82 OtelString::Owned(s) => s.to_string(),
83 OtelString::Static(s) => s.to_string(),
84 OtelString::RefCounted(s) => s.to_string(),
85 }
86 }
87}
88
89impl fmt::Display for Key {
90 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
91 match &self.0 {
92 OtelString::Owned(s) => s.fmt(fmt),
93 OtelString::Static(s) => s.fmt(fmt),
94 OtelString::RefCounted(s) => s.fmt(fmt),
95 }
96 }
97}
98
99impl Borrow<str> for Key {
100 fn borrow(&self) -> &str {
101 self.0.as_str()
102 }
103}
104
105impl AsRef<str> for Key {
106 fn as_ref(&self) -> &str {
107 self.0.as_str()
108 }
109}
110
111#[derive(Clone, Debug, Eq)]
112enum OtelString {
113 Owned(Box<str>),
114 Static(&'static str),
115 RefCounted(Arc<str>),
116}
117
118impl OtelString {
119 fn as_str(&self) -> &str {
120 match self {
121 OtelString::Owned(s) => s.as_ref(),
122 OtelString::Static(s) => s,
123 OtelString::RefCounted(s) => s.as_ref(),
124 }
125 }
126}
127
128impl PartialOrd for OtelString {
129 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
130 Some(self.cmp(other))
131 }
132}
133
134impl Ord for OtelString {
135 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
136 self.as_str().cmp(other.as_str())
137 }
138}
139
140impl PartialEq for OtelString {
141 fn eq(&self, other: &Self) -> bool {
142 self.as_str().eq(other.as_str())
143 }
144}
145
146impl hash::Hash for OtelString {
147 fn hash<H: hash::Hasher>(&self, state: &mut H) {
148 self.as_str().hash(state)
149 }
150}
151
152#[non_exhaustive]
154#[derive(Clone, Debug, PartialEq)]
155pub enum Array {
156 Bool(Vec<bool>),
158 I64(Vec<i64>),
160 F64(Vec<f64>),
162 String(Vec<StringValue>),
164}
165
166impl fmt::Display for Array {
167 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
168 match self {
169 Array::Bool(values) => display_array_str(values, fmt),
170 Array::I64(values) => display_array_str(values, fmt),
171 Array::F64(values) => display_array_str(values, fmt),
172 Array::String(values) => {
173 write!(fmt, "[")?;
174 for (i, t) in values.iter().enumerate() {
175 if i > 0 {
176 write!(fmt, ",")?;
177 }
178 write!(fmt, "\"{}\"", t)?;
179 }
180 write!(fmt, "]")
181 }
182 }
183 }
184}
185
186fn display_array_str<T: fmt::Display>(slice: &[T], fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
187 write!(fmt, "[")?;
188 for (i, t) in slice.iter().enumerate() {
189 if i > 0 {
190 write!(fmt, ",")?;
191 }
192 write!(fmt, "{}", t)?;
193 }
194 write!(fmt, "]")
195}
196
197macro_rules! into_array {
198 ($(($t:ty, $val:expr),)+) => {
199 $(
200 impl From<$t> for Array {
201 fn from(t: $t) -> Self {
202 $val(t)
203 }
204 }
205 )+
206 }
207}
208
209into_array!(
210 (Vec<bool>, Array::Bool),
211 (Vec<i64>, Array::I64),
212 (Vec<f64>, Array::F64),
213 (Vec<StringValue>, Array::String),
214);
215
216#[non_exhaustive]
218#[derive(Clone, Debug, PartialEq)]
219pub enum Value {
220 Bool(bool),
222 I64(i64),
224 F64(f64),
226 String(StringValue),
228 Array(Array),
230}
231
232#[non_exhaustive]
234#[derive(Clone, PartialEq, Eq, Hash)]
235pub struct StringValue(OtelString);
236
237impl fmt::Debug for StringValue {
238 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
239 self.0.fmt(f)
240 }
241}
242
243impl fmt::Display for StringValue {
244 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
245 match &self.0 {
246 OtelString::Owned(s) => s.fmt(f),
247 OtelString::Static(s) => s.fmt(f),
248 OtelString::RefCounted(s) => s.fmt(f),
249 }
250 }
251}
252
253impl AsRef<str> for StringValue {
254 fn as_ref(&self) -> &str {
255 self.0.as_str()
256 }
257}
258
259impl StringValue {
260 pub fn as_str(&self) -> &str {
262 self.0.as_str()
263 }
264}
265
266impl From<StringValue> for String {
267 fn from(s: StringValue) -> Self {
268 match s.0 {
269 OtelString::Owned(s) => s.to_string(),
270 OtelString::Static(s) => s.to_string(),
271 OtelString::RefCounted(s) => s.to_string(),
272 }
273 }
274}
275
276impl From<&'static str> for StringValue {
277 fn from(s: &'static str) -> Self {
278 StringValue(OtelString::Static(s))
279 }
280}
281
282impl From<String> for StringValue {
283 fn from(s: String) -> Self {
284 StringValue(OtelString::Owned(s.into_boxed_str()))
285 }
286}
287
288impl From<Arc<str>> for StringValue {
289 fn from(s: Arc<str>) -> Self {
290 StringValue(OtelString::RefCounted(s))
291 }
292}
293
294impl From<Cow<'static, str>> for StringValue {
295 fn from(s: Cow<'static, str>) -> Self {
296 match s {
297 Cow::Owned(s) => StringValue(OtelString::Owned(s.into_boxed_str())),
298 Cow::Borrowed(s) => StringValue(OtelString::Static(s)),
299 }
300 }
301}
302
303impl Value {
304 pub fn as_str(&self) -> Cow<'_, str> {
308 match self {
309 Value::Bool(v) => format!("{}", v).into(),
310 Value::I64(v) => format!("{}", v).into(),
311 Value::F64(v) => format!("{}", v).into(),
312 Value::String(v) => Cow::Borrowed(v.as_str()),
313 Value::Array(v) => format!("{}", v).into(),
314 }
315 }
316}
317
318macro_rules! from_values {
319 (
320 $(
321 ($t:ty, $val:expr);
322 )+
323 ) => {
324 $(
325 impl From<$t> for Value {
326 fn from(t: $t) -> Self {
327 $val(t)
328 }
329 }
330 )+
331 }
332}
333
334from_values!(
335 (bool, Value::Bool);
336 (i64, Value::I64);
337 (f64, Value::F64);
338 (StringValue, Value::String);
339);
340
341impl From<&'static str> for Value {
342 fn from(s: &'static str) -> Self {
343 Value::String(s.into())
344 }
345}
346
347impl From<String> for Value {
348 fn from(s: String) -> Self {
349 Value::String(s.into())
350 }
351}
352
353impl From<Arc<str>> for Value {
354 fn from(s: Arc<str>) -> Self {
355 Value::String(s.into())
356 }
357}
358
359impl From<Cow<'static, str>> for Value {
360 fn from(s: Cow<'static, str>) -> Self {
361 Value::String(s.into())
362 }
363}
364
365impl fmt::Display for Value {
366 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
367 match self {
368 Value::Bool(v) => v.fmt(fmt),
369 Value::I64(v) => v.fmt(fmt),
370 Value::F64(v) => v.fmt(fmt),
371 Value::String(v) => fmt.write_str(v.as_str()),
372 Value::Array(v) => v.fmt(fmt),
373 }
374 }
375}
376
377#[derive(Clone, Debug, PartialEq)]
379#[non_exhaustive]
380pub struct KeyValue {
381 pub key: Key,
383
384 pub value: Value,
386}
387
388impl KeyValue {
389 pub fn new<K, V>(key: K, value: V) -> Self
391 where
392 K: Into<Key>,
393 V: Into<Value>,
394 {
395 KeyValue {
396 key: key.into(),
397 value: value.into(),
398 }
399 }
400}
401
402#[derive(Debug, Default, Clone)]
411#[non_exhaustive]
412pub struct InstrumentationScope {
413 name: Cow<'static, str>,
417
418 version: Option<Cow<'static, str>>,
420
421 schema_url: Option<Cow<'static, str>>,
425
426 attributes: Vec<KeyValue>,
428}
429
430impl Eq for InstrumentationScope {}
432
433impl PartialEq for InstrumentationScope {
434 fn eq(&self, other: &Self) -> bool {
435 self.name == other.name
436 && self.version == other.version
437 && self.schema_url == other.schema_url
438 }
439}
440
441impl hash::Hash for InstrumentationScope {
442 fn hash<H: hash::Hasher>(&self, state: &mut H) {
443 self.name.hash(state);
444 self.version.hash(state);
445 self.schema_url.hash(state);
446 }
447}
448
449impl InstrumentationScope {
450 pub fn builder<T: Into<Cow<'static, str>>>(name: T) -> InstrumentationScopeBuilder {
452 InstrumentationScopeBuilder {
453 name: name.into(),
454 version: None,
455 schema_url: None,
456 attributes: None,
457 }
458 }
459
460 #[inline]
462 pub fn name(&self) -> &str {
463 &self.name
464 }
465
466 #[inline]
468 pub fn version(&self) -> Option<&str> {
469 self.version.as_deref()
470 }
471
472 #[inline]
476 pub fn schema_url(&self) -> Option<&str> {
477 self.schema_url.as_deref()
478 }
479
480 #[inline]
482 pub fn attributes(&self) -> impl Iterator<Item = &KeyValue> {
483 self.attributes.iter()
484 }
485}
486
487#[derive(Debug)]
499pub struct InstrumentationScopeBuilder {
500 name: Cow<'static, str>,
501 version: Option<Cow<'static, str>>,
502 schema_url: Option<Cow<'static, str>>,
503 attributes: Option<Vec<KeyValue>>,
504}
505
506impl InstrumentationScopeBuilder {
507 pub fn with_version(mut self, version: impl Into<Cow<'static, str>>) -> Self {
517 self.version = Some(version.into());
518 self
519 }
520
521 pub fn with_schema_url(mut self, schema_url: impl Into<Cow<'static, str>>) -> Self {
531 self.schema_url = Some(schema_url.into());
532 self
533 }
534
535 pub fn with_attributes<I>(mut self, attributes: I) -> Self
547 where
548 I: IntoIterator<Item = KeyValue>,
549 {
550 self.attributes = Some(attributes.into_iter().collect());
551 self
552 }
553
554 pub fn build(self) -> InstrumentationScope {
556 InstrumentationScope {
557 name: self.name,
558 version: self.version,
559 schema_url: self.schema_url,
560 attributes: self.attributes.unwrap_or_default(),
561 }
562 }
563}