1use std::borrow::{Borrow, Cow};
2use std::sync::Arc;
3use std::{fmt, hash};
4
5#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
11pub struct Key(OtelString);
12
13impl Key {
14 pub fn new(value: impl Into<Key>) -> Self {
27 value.into()
28 }
29
30 pub const fn from_static_str(value: &'static str) -> Self {
32 Key(OtelString::Static(value))
33 }
34
35 pub fn bool<T: Into<bool>>(self, value: T) -> KeyValue {
37 KeyValue {
38 key: self,
39 value: Value::Bool(value.into()),
40 }
41 }
42
43 pub fn i64(self, value: i64) -> KeyValue {
45 KeyValue {
46 key: self,
47 value: Value::I64(value),
48 }
49 }
50
51 pub fn f64(self, value: f64) -> KeyValue {
53 KeyValue {
54 key: self,
55 value: Value::F64(value),
56 }
57 }
58
59 pub fn string(self, value: impl Into<StringValue>) -> KeyValue {
61 KeyValue {
62 key: self,
63 value: Value::String(value.into()),
64 }
65 }
66
67 pub fn array<T: Into<Array>>(self, value: T) -> KeyValue {
69 KeyValue {
70 key: self,
71 value: Value::Array(value.into()),
72 }
73 }
74
75 pub fn as_str(&self) -> &str {
77 self.0.as_str()
78 }
79}
80
81impl From<&'static str> for Key {
82 fn from(key_str: &'static str) -> Self {
84 Key(OtelString::Static(key_str))
85 }
86}
87
88impl From<String> for Key {
89 fn from(string: String) -> Self {
91 Key(OtelString::Owned(string.into_boxed_str()))
92 }
93}
94
95impl From<Arc<str>> for Key {
96 fn from(string: Arc<str>) -> Self {
98 Key(OtelString::RefCounted(string))
99 }
100}
101
102impl From<Cow<'static, str>> for Key {
103 fn from(string: Cow<'static, str>) -> Self {
105 match string {
106 Cow::Borrowed(s) => Key(OtelString::Static(s)),
107 Cow::Owned(s) => Key(OtelString::Owned(s.into_boxed_str())),
108 }
109 }
110}
111
112impl fmt::Debug for Key {
113 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
114 self.0.fmt(fmt)
115 }
116}
117
118impl From<Key> for String {
119 fn from(key: Key) -> Self {
120 match key.0 {
121 OtelString::Owned(s) => s.to_string(),
122 OtelString::Static(s) => s.to_string(),
123 OtelString::RefCounted(s) => s.to_string(),
124 }
125 }
126}
127
128impl fmt::Display for Key {
129 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
130 match &self.0 {
131 OtelString::Owned(s) => s.fmt(fmt),
132 OtelString::Static(s) => s.fmt(fmt),
133 OtelString::RefCounted(s) => s.fmt(fmt),
134 }
135 }
136}
137
138impl Borrow<str> for Key {
139 fn borrow(&self) -> &str {
140 self.0.as_str()
141 }
142}
143
144impl AsRef<str> for Key {
145 fn as_ref(&self) -> &str {
146 self.0.as_str()
147 }
148}
149
150#[derive(Clone, Debug, Eq)]
151enum OtelString {
152 Owned(Box<str>),
153 Static(&'static str),
154 RefCounted(Arc<str>),
155}
156
157impl OtelString {
158 fn as_str(&self) -> &str {
159 match self {
160 OtelString::Owned(s) => s.as_ref(),
161 OtelString::Static(s) => s,
162 OtelString::RefCounted(s) => s.as_ref(),
163 }
164 }
165}
166
167impl PartialOrd for OtelString {
168 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
169 Some(self.cmp(other))
170 }
171}
172
173impl Ord for OtelString {
174 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
175 self.as_str().cmp(other.as_str())
176 }
177}
178
179impl PartialEq for OtelString {
180 fn eq(&self, other: &Self) -> bool {
181 self.as_str().eq(other.as_str())
182 }
183}
184
185impl hash::Hash for OtelString {
186 fn hash<H: hash::Hasher>(&self, state: &mut H) {
187 self.as_str().hash(state)
188 }
189}
190
191#[derive(Clone, Debug, PartialEq)]
193pub enum Array {
194 Bool(Vec<bool>),
196 I64(Vec<i64>),
198 F64(Vec<f64>),
200 String(Vec<StringValue>),
202}
203
204impl fmt::Display for Array {
205 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
206 match self {
207 Array::Bool(values) => display_array_str(values, fmt),
208 Array::I64(values) => display_array_str(values, fmt),
209 Array::F64(values) => display_array_str(values, fmt),
210 Array::String(values) => {
211 write!(fmt, "[")?;
212 for (i, t) in values.iter().enumerate() {
213 if i > 0 {
214 write!(fmt, ",")?;
215 }
216 write!(fmt, "\"{}\"", t)?;
217 }
218 write!(fmt, "]")
219 }
220 }
221 }
222}
223
224fn display_array_str<T: fmt::Display>(slice: &[T], fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
225 write!(fmt, "[")?;
226 for (i, t) in slice.iter().enumerate() {
227 if i > 0 {
228 write!(fmt, ",")?;
229 }
230 write!(fmt, "{}", t)?;
231 }
232 write!(fmt, "]")
233}
234
235macro_rules! into_array {
236 ($(($t:ty, $val:expr),)+) => {
237 $(
238 impl From<$t> for Array {
239 fn from(t: $t) -> Self {
240 $val(t)
241 }
242 }
243 )+
244 }
245}
246
247into_array!(
248 (Vec<bool>, Array::Bool),
249 (Vec<i64>, Array::I64),
250 (Vec<f64>, Array::F64),
251 (Vec<StringValue>, Array::String),
252);
253
254#[derive(Clone, Debug, PartialEq)]
256pub enum Value {
257 Bool(bool),
259 I64(i64),
261 F64(f64),
263 String(StringValue),
265 Array(Array),
267}
268
269#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
271pub struct StringValue(OtelString);
272
273impl fmt::Debug for StringValue {
274 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
275 self.0.fmt(f)
276 }
277}
278
279impl fmt::Display for StringValue {
280 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
281 match &self.0 {
282 OtelString::Owned(s) => s.fmt(f),
283 OtelString::Static(s) => s.fmt(f),
284 OtelString::RefCounted(s) => s.fmt(f),
285 }
286 }
287}
288
289impl AsRef<str> for StringValue {
290 fn as_ref(&self) -> &str {
291 self.0.as_str()
292 }
293}
294
295impl StringValue {
296 pub fn as_str(&self) -> &str {
298 self.0.as_str()
299 }
300}
301
302impl From<StringValue> for String {
303 fn from(s: StringValue) -> Self {
304 match s.0 {
305 OtelString::Owned(s) => s.to_string(),
306 OtelString::Static(s) => s.to_string(),
307 OtelString::RefCounted(s) => s.to_string(),
308 }
309 }
310}
311
312impl From<&'static str> for StringValue {
313 fn from(s: &'static str) -> Self {
314 StringValue(OtelString::Static(s))
315 }
316}
317
318impl From<String> for StringValue {
319 fn from(s: String) -> Self {
320 StringValue(OtelString::Owned(s.into_boxed_str()))
321 }
322}
323
324impl From<Arc<str>> for StringValue {
325 fn from(s: Arc<str>) -> Self {
326 StringValue(OtelString::RefCounted(s))
327 }
328}
329
330impl From<Cow<'static, str>> for StringValue {
331 fn from(s: Cow<'static, str>) -> Self {
332 match s {
333 Cow::Owned(s) => StringValue(OtelString::Owned(s.into_boxed_str())),
334 Cow::Borrowed(s) => StringValue(OtelString::Static(s)),
335 }
336 }
337}
338
339impl Value {
340 pub fn as_str(&self) -> Cow<'_, str> {
344 match self {
345 Value::Bool(v) => format!("{}", v).into(),
346 Value::I64(v) => format!("{}", v).into(),
347 Value::F64(v) => format!("{}", v).into(),
348 Value::String(v) => Cow::Borrowed(v.as_str()),
349 Value::Array(v) => format!("{}", v).into(),
350 }
351 }
352}
353
354macro_rules! from_values {
355 (
356 $(
357 ($t:ty, $val:expr);
358 )+
359 ) => {
360 $(
361 impl From<$t> for Value {
362 fn from(t: $t) -> Self {
363 $val(t)
364 }
365 }
366 )+
367 }
368}
369
370from_values!(
371 (bool, Value::Bool);
372 (i64, Value::I64);
373 (f64, Value::F64);
374 (StringValue, Value::String);
375);
376
377impl From<&'static str> for Value {
378 fn from(s: &'static str) -> Self {
379 Value::String(s.into())
380 }
381}
382
383impl From<String> for Value {
384 fn from(s: String) -> Self {
385 Value::String(s.into())
386 }
387}
388
389impl From<Arc<str>> for Value {
390 fn from(s: Arc<str>) -> Self {
391 Value::String(s.into())
392 }
393}
394
395impl From<Cow<'static, str>> for Value {
396 fn from(s: Cow<'static, str>) -> Self {
397 Value::String(s.into())
398 }
399}
400
401impl fmt::Display for Value {
402 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
403 match self {
404 Value::Bool(v) => v.fmt(fmt),
405 Value::I64(v) => v.fmt(fmt),
406 Value::F64(v) => v.fmt(fmt),
407 Value::String(v) => fmt.write_str(v.as_str()),
408 Value::Array(v) => v.fmt(fmt),
409 }
410 }
411}
412
413#[derive(Clone, Debug, PartialEq)]
415pub struct KeyValue {
416 pub key: Key,
418
419 pub value: Value,
421}
422
423impl KeyValue {
424 pub fn new<K, V>(key: K, value: V) -> Self
426 where
427 K: Into<Key>,
428 V: Into<Value>,
429 {
430 KeyValue {
431 key: key.into(),
432 value: value.into(),
433 }
434 }
435}
436
437pub trait ExportError: std::error::Error + Send + Sync + 'static {
439 fn exporter_name(&self) -> &'static str;
441}
442
443#[derive(Debug, Default, Clone)]
452#[non_exhaustive]
453pub struct InstrumentationLibrary {
454 pub name: Cow<'static, str>,
458
459 pub version: Option<Cow<'static, str>>,
470
471 pub schema_url: Option<Cow<'static, str>>,
475
476 pub attributes: Vec<KeyValue>,
478}
479
480impl Eq for InstrumentationLibrary {}
482
483impl PartialEq for InstrumentationLibrary {
484 fn eq(&self, other: &Self) -> bool {
485 self.name == other.name
486 && self.version == other.version
487 && self.schema_url == other.schema_url
488 }
489}
490
491impl hash::Hash for InstrumentationLibrary {
492 fn hash<H: hash::Hasher>(&self, state: &mut H) {
493 self.name.hash(state);
494 self.version.hash(state);
495 self.schema_url.hash(state);
496 }
497}
498
499impl InstrumentationLibrary {
500 #[deprecated(since = "0.23.0", note = "Please use builder() instead")]
504 pub fn new(
505 name: impl Into<Cow<'static, str>>,
506 version: Option<impl Into<Cow<'static, str>>>,
507 schema_url: Option<impl Into<Cow<'static, str>>>,
508 attributes: Option<Vec<KeyValue>>,
509 ) -> InstrumentationLibrary {
510 InstrumentationLibrary {
511 name: name.into(),
512 version: version.map(Into::into),
513 schema_url: schema_url.map(Into::into),
514 attributes: attributes.unwrap_or_default(),
515 }
516 }
517
518 pub fn builder<T: Into<Cow<'static, str>>>(name: T) -> InstrumentationLibraryBuilder {
520 InstrumentationLibraryBuilder {
521 name: name.into(),
522 version: None,
523 schema_url: None,
524 attributes: None,
525 }
526 }
527}
528
529#[derive(Debug)]
541pub struct InstrumentationLibraryBuilder {
542 name: Cow<'static, str>,
543
544 version: Option<Cow<'static, str>>,
545
546 schema_url: Option<Cow<'static, str>>,
547
548 attributes: Option<Vec<KeyValue>>,
549}
550
551impl InstrumentationLibraryBuilder {
552 pub fn with_version(mut self, version: impl Into<Cow<'static, str>>) -> Self {
562 self.version = Some(version.into());
563 self
564 }
565
566 pub fn with_schema_url(mut self, schema_url: impl Into<Cow<'static, str>>) -> Self {
576 self.schema_url = Some(schema_url.into());
577 self
578 }
579
580 pub fn with_attributes<I>(mut self, attributes: I) -> Self
592 where
593 I: IntoIterator<Item = KeyValue>,
594 {
595 self.attributes = Some(attributes.into_iter().collect());
596 self
597 }
598
599 pub fn build(self) -> InstrumentationLibrary {
601 InstrumentationLibrary {
602 name: self.name,
603 version: self.version,
604 schema_url: self.schema_url,
605 attributes: self.attributes.unwrap_or_default(),
606 }
607 }
608}