use std::borrow::Cow;
use facet::Facet;
#[repr(u8)]
#[derive(Debug, Clone, PartialEq, Eq, Facet)]
pub enum MetadataValue<'a> {
String(Cow<'a, str>) = 0,
Bytes(Cow<'a, [u8]>) = 1,
U64(u64) = 2,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Facet)]
#[repr(transparent)]
#[facet(transparent)]
pub struct MetadataFlags(u64);
impl MetadataFlags {
pub const NONE: Self = Self(0);
pub const SENSITIVE: Self = Self(1 << 0);
pub const NO_PROPAGATE: Self = Self(1 << 1);
pub fn contains(self, other: Self) -> bool {
(self.0 & other.0) == other.0
}
}
impl std::ops::BitOr for MetadataFlags {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
Self(self.0 | rhs.0)
}
}
impl std::ops::BitOrAssign for MetadataFlags {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
impl std::ops::BitAnd for MetadataFlags {
type Output = Self;
fn bitand(self, rhs: Self) -> Self {
Self(self.0 & rhs.0)
}
}
impl std::ops::BitAndAssign for MetadataFlags {
fn bitand_assign(&mut self, rhs: Self) {
self.0 &= rhs.0;
}
}
#[derive(Debug, Clone, PartialEq, Eq, Facet)]
pub struct MetadataEntry<'a> {
pub key: Cow<'a, str>,
pub value: MetadataValue<'a>,
pub flags: MetadataFlags,
}
impl<'a> MetadataValue<'a> {
pub fn into_owned(self) -> MetadataValue<'static> {
match self {
MetadataValue::String(s) => MetadataValue::String(Cow::Owned(s.into_owned())),
MetadataValue::Bytes(b) => MetadataValue::Bytes(Cow::Owned(b.into_owned())),
MetadataValue::U64(n) => MetadataValue::U64(n),
}
}
}
impl<'a> MetadataEntry<'a> {
pub fn str(key: impl Into<Cow<'a, str>>, value: impl Into<Cow<'a, str>>) -> Self {
MetadataEntry {
key: key.into(),
value: MetadataValue::String(value.into()),
flags: MetadataFlags::NONE,
}
}
pub fn u64(key: impl Into<Cow<'a, str>>, value: u64) -> Self {
MetadataEntry {
key: key.into(),
value: MetadataValue::U64(value),
flags: MetadataFlags::NONE,
}
}
pub fn bytes(key: impl Into<Cow<'a, str>>, value: impl Into<Cow<'a, [u8]>>) -> Self {
MetadataEntry {
key: key.into(),
value: MetadataValue::Bytes(value.into()),
flags: MetadataFlags::NONE,
}
}
pub fn with_flags(mut self, flags: MetadataFlags) -> Self {
self.flags = flags;
self
}
pub fn into_owned(self) -> MetadataEntry<'static> {
MetadataEntry {
key: Cow::Owned(self.key.into_owned()),
value: self.value.into_owned(),
flags: self.flags,
}
}
}
pub struct MetadataBuilder<'a> {
entries: Metadata<'a>,
}
impl<'a> MetadataBuilder<'a> {
pub fn str(mut self, key: impl Into<Cow<'a, str>>, value: impl Into<Cow<'a, str>>) -> Self {
self.entries.push(MetadataEntry::str(key, value));
self
}
pub fn u64(mut self, key: impl Into<Cow<'a, str>>, value: u64) -> Self {
self.entries.push(MetadataEntry::u64(key, value));
self
}
pub fn bytes(mut self, key: impl Into<Cow<'a, str>>, value: impl Into<Cow<'a, [u8]>>) -> Self {
self.entries.push(MetadataEntry::bytes(key, value));
self
}
pub fn done(self) -> Metadata<'a> {
self.entries
}
}
pub fn metadata_build<'a>() -> MetadataBuilder<'a> {
MetadataBuilder {
entries: Vec::new(),
}
}
pub type Metadata<'a> = Vec<MetadataEntry<'a>>;
pub fn metadata_into_owned(metadata: Metadata<'_>) -> Metadata<'static> {
metadata
.into_iter()
.map(MetadataEntry::into_owned)
.collect()
}
pub fn metadata_get_str<'a>(metadata: &'a [MetadataEntry<'a>], key: &str) -> Option<&'a str> {
metadata.iter().find_map(|e| {
if e.key == key {
match &e.value {
MetadataValue::String(s) => Some(s.as_ref()),
_ => None,
}
} else {
None
}
})
}
pub fn metadata_get_u64(metadata: &[MetadataEntry], key: &str) -> Option<u64> {
metadata.iter().find_map(|e| {
if e.key == key {
match &e.value {
MetadataValue::U64(n) => Some(*n),
_ => None,
}
} else {
None
}
})
}