use std::borrow::Cow;
use std::sync::Arc;
use std::{fmt, hash};
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Key(OtelString);
impl Key {
pub fn new(value: impl Into<Key>) -> Self {
value.into()
}
pub const fn from_static_str(value: &'static str) -> Self {
Key(OtelString::Static(value))
}
pub fn bool<T: Into<bool>>(self, value: T) -> KeyValue {
KeyValue {
key: self,
value: Value::Bool(value.into()),
}
}
pub fn i64(self, value: i64) -> KeyValue {
KeyValue {
key: self,
value: Value::I64(value),
}
}
pub fn f64(self, value: f64) -> KeyValue {
KeyValue {
key: self,
value: Value::F64(value),
}
}
pub fn string(self, value: impl Into<StringValue>) -> KeyValue {
KeyValue {
key: self,
value: Value::String(value.into()),
}
}
pub fn array<T: Into<Array>>(self, value: T) -> KeyValue {
KeyValue {
key: self,
value: Value::Array(value.into()),
}
}
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
impl From<&'static str> for Key {
fn from(key_str: &'static str) -> Self {
Key(OtelString::Static(key_str))
}
}
impl From<String> for Key {
fn from(string: String) -> Self {
Key(OtelString::Owned(string.into_boxed_str()))
}
}
impl From<Arc<str>> for Key {
fn from(string: Arc<str>) -> Self {
Key(OtelString::RefCounted(string))
}
}
impl From<Cow<'static, str>> for Key {
fn from(string: Cow<'static, str>) -> Self {
match string {
Cow::Borrowed(s) => Key(OtelString::Static(s)),
Cow::Owned(s) => Key(OtelString::Owned(s.into_boxed_str())),
}
}
}
impl fmt::Debug for Key {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(fmt)
}
}
impl From<Key> for String {
fn from(key: Key) -> Self {
match key.0 {
OtelString::Owned(s) => s.to_string(),
OtelString::Static(s) => s.to_string(),
OtelString::RefCounted(s) => s.to_string(),
}
}
}
impl fmt::Display for Key {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.0 {
OtelString::Owned(s) => s.fmt(fmt),
OtelString::Static(s) => s.fmt(fmt),
OtelString::RefCounted(s) => s.fmt(fmt),
}
}
}
#[derive(Clone, Debug, Eq)]
enum OtelString {
Owned(Box<str>),
Static(&'static str),
RefCounted(Arc<str>),
}
impl OtelString {
fn as_str(&self) -> &str {
match self {
OtelString::Owned(s) => s.as_ref(),
OtelString::Static(s) => s,
OtelString::RefCounted(s) => s.as_ref(),
}
}
}
impl PartialOrd for OtelString {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.as_str().partial_cmp(other.as_str())
}
}
impl Ord for OtelString {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.as_str().cmp(other.as_str())
}
}
impl PartialEq for OtelString {
fn eq(&self, other: &Self) -> bool {
self.as_str().eq(other.as_str())
}
}
impl hash::Hash for OtelString {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.as_str().hash(state)
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Array {
Bool(Vec<bool>),
I64(Vec<i64>),
F64(Vec<f64>),
String(Vec<StringValue>),
}
impl fmt::Display for Array {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Array::Bool(values) => display_array_str(values, fmt),
Array::I64(values) => display_array_str(values, fmt),
Array::F64(values) => display_array_str(values, fmt),
Array::String(values) => {
write!(fmt, "[")?;
for (i, t) in values.iter().enumerate() {
if i > 0 {
write!(fmt, ",")?;
}
write!(fmt, "\"{}\"", t)?;
}
write!(fmt, "]")
}
}
}
}
fn display_array_str<T: fmt::Display>(slice: &[T], fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "[")?;
for (i, t) in slice.iter().enumerate() {
if i > 0 {
write!(fmt, ",")?;
}
write!(fmt, "{}", t)?;
}
write!(fmt, "]")
}
macro_rules! into_array {
($(($t:ty, $val:expr),)+) => {
$(
impl From<$t> for Array {
fn from(t: $t) -> Self {
$val(t)
}
}
)+
}
}
into_array!(
(Vec<bool>, Array::Bool),
(Vec<i64>, Array::I64),
(Vec<f64>, Array::F64),
(Vec<StringValue>, Array::String),
);
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
Bool(bool),
I64(i64),
F64(f64),
String(StringValue),
Array(Array),
}
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct StringValue(OtelString);
impl fmt::Debug for StringValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl fmt::Display for StringValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.0 {
OtelString::Owned(s) => s.fmt(f),
OtelString::Static(s) => s.fmt(f),
OtelString::RefCounted(s) => s.fmt(f),
}
}
}
impl AsRef<str> for StringValue {
fn as_ref(&self) -> &str {
self.0.as_str()
}
}
impl StringValue {
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
impl From<StringValue> for String {
fn from(s: StringValue) -> Self {
match s.0 {
OtelString::Owned(s) => s.to_string(),
OtelString::Static(s) => s.to_string(),
OtelString::RefCounted(s) => s.to_string(),
}
}
}
impl From<&'static str> for StringValue {
fn from(s: &'static str) -> Self {
StringValue(OtelString::Static(s))
}
}
impl From<String> for StringValue {
fn from(s: String) -> Self {
StringValue(OtelString::Owned(s.into_boxed_str()))
}
}
impl From<Arc<str>> for StringValue {
fn from(s: Arc<str>) -> Self {
StringValue(OtelString::RefCounted(s))
}
}
impl From<Cow<'static, str>> for StringValue {
fn from(s: Cow<'static, str>) -> Self {
match s {
Cow::Owned(s) => StringValue(OtelString::Owned(s.into_boxed_str())),
Cow::Borrowed(s) => StringValue(OtelString::Static(s)),
}
}
}
impl Value {
pub fn as_str(&self) -> Cow<'_, str> {
match self {
Value::Bool(v) => format!("{}", v).into(),
Value::I64(v) => format!("{}", v).into(),
Value::F64(v) => format!("{}", v).into(),
Value::String(v) => Cow::Borrowed(v.as_str()),
Value::Array(v) => format!("{}", v).into(),
}
}
}
macro_rules! from_values {
(
$(
($t:ty, $val:expr);
)+
) => {
$(
impl From<$t> for Value {
fn from(t: $t) -> Self {
$val(t)
}
}
)+
}
}
from_values!(
(bool, Value::Bool);
(i64, Value::I64);
(f64, Value::F64);
(StringValue, Value::String);
);
impl From<&'static str> for Value {
fn from(s: &'static str) -> Self {
Value::String(s.into())
}
}
impl From<String> for Value {
fn from(s: String) -> Self {
Value::String(s.into())
}
}
impl From<Arc<str>> for Value {
fn from(s: Arc<str>) -> Self {
Value::String(s.into())
}
}
impl From<Cow<'static, str>> for Value {
fn from(s: Cow<'static, str>) -> Self {
Value::String(s.into())
}
}
impl fmt::Display for Value {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Value::Bool(v) => v.fmt(fmt),
Value::I64(v) => v.fmt(fmt),
Value::F64(v) => v.fmt(fmt),
Value::String(v) => fmt.write_str(v.as_str()),
Value::Array(v) => v.fmt(fmt),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct KeyValue {
pub key: Key,
pub value: Value,
}
impl KeyValue {
pub fn new<K, V>(key: K, value: V) -> Self
where
K: Into<Key>,
V: Into<Value>,
{
KeyValue {
key: key.into(),
value: value.into(),
}
}
}
pub trait ExportError: std::error::Error + Send + Sync + 'static {
fn exporter_name(&self) -> &'static str;
}
#[derive(Debug, Default, Clone)]
#[non_exhaustive]
pub struct InstrumentationLibrary {
pub name: Cow<'static, str>,
pub version: Option<Cow<'static, str>>,
pub schema_url: Option<Cow<'static, str>>,
pub attributes: Vec<KeyValue>,
}
impl Eq for InstrumentationLibrary {}
impl PartialEq for InstrumentationLibrary {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
&& self.version == other.version
&& self.schema_url == other.schema_url
}
}
impl hash::Hash for InstrumentationLibrary {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.name.hash(state);
self.version.hash(state);
self.schema_url.hash(state);
}
}
impl InstrumentationLibrary {
pub fn new(
name: impl Into<Cow<'static, str>>,
version: Option<impl Into<Cow<'static, str>>>,
schema_url: Option<impl Into<Cow<'static, str>>>,
attributes: Option<Vec<KeyValue>>,
) -> InstrumentationLibrary {
InstrumentationLibrary {
name: name.into(),
version: version.map(Into::into),
schema_url: schema_url.map(Into::into),
attributes: attributes.unwrap_or_default(),
}
}
}