use alloc::{
borrow::Cow,
string::{String, ToString},
};
use core::{convert::TryInto, fmt, sync::atomic::AtomicU16};
use zenoh_keyexpr::{keyexpr, OwnedKeyExpr};
use zenoh_result::{bail, ZResult};
use crate::network::Mapping;
pub type ExprId = u16;
pub type ExprLen = u16;
pub type AtomicExprId = AtomicU16;
pub const EMPTY_EXPR_ID: ExprId = 0;
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
pub struct WireExpr<'a> {
pub scope: ExprId, pub suffix: Cow<'a, str>,
pub mapping: Mapping,
}
impl<'a> WireExpr<'a> {
pub fn empty() -> Self {
WireExpr {
scope: 0,
suffix: "".into(),
mapping: Mapping::Sender,
}
}
pub fn is_empty(&self) -> bool {
self.scope == 0 && self.suffix.as_ref().is_empty()
}
pub fn as_str(&'a self) -> &'a str {
if self.scope == 0 {
self.suffix.as_ref()
} else {
"<encoded_expr>"
}
}
pub fn try_as_str(&'a self) -> ZResult<&'a str> {
if self.scope == EMPTY_EXPR_ID {
Ok(self.suffix.as_ref())
} else {
bail!("Scoped key expression")
}
}
pub fn as_id(&'a self) -> ExprId {
self.scope
}
pub fn try_as_id(&'a self) -> ZResult<ExprId> {
if self.has_suffix() {
bail!("Suffixed key expression")
} else {
Ok(self.scope)
}
}
pub fn as_id_and_suffix(&'a self) -> (ExprId, &'a str) {
(self.scope, self.suffix.as_ref())
}
pub fn has_suffix(&self) -> bool {
!self.suffix.as_ref().is_empty()
}
pub fn to_owned(&self) -> WireExpr<'static> {
WireExpr {
scope: self.scope,
suffix: self.suffix.to_string().into(),
mapping: self.mapping,
}
}
pub fn with_suffix(mut self, suffix: &'a str) -> Self {
if self.suffix.is_empty() {
self.suffix = suffix.into();
} else {
self.suffix += suffix;
}
self
}
}
impl TryInto<String> for WireExpr<'_> {
type Error = zenoh_result::Error;
fn try_into(self) -> Result<String, Self::Error> {
if self.scope == 0 {
Ok(self.suffix.into_owned())
} else {
bail!("Scoped key expression")
}
}
}
impl TryInto<ExprId> for WireExpr<'_> {
type Error = zenoh_result::Error;
fn try_into(self) -> Result<ExprId, Self::Error> {
self.try_as_id()
}
}
impl From<ExprId> for WireExpr<'_> {
fn from(scope: ExprId) -> Self {
Self {
scope,
suffix: "".into(),
mapping: Mapping::Sender,
}
}
}
impl<'a> From<&'a OwnedKeyExpr> for WireExpr<'a> {
fn from(val: &'a OwnedKeyExpr) -> Self {
WireExpr {
scope: 0,
suffix: Cow::Borrowed(val.as_str()),
mapping: Mapping::Sender,
}
}
}
impl<'a> From<&'a keyexpr> for WireExpr<'a> {
fn from(val: &'a keyexpr) -> Self {
WireExpr {
scope: 0,
suffix: Cow::Borrowed(val.as_str()),
mapping: Mapping::Sender,
}
}
}
impl fmt::Display for WireExpr<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.scope == 0 {
write!(f, "{}", self.suffix)
} else {
write!(f, "{}:{:?}:{}", self.scope, self.mapping, self.suffix)
}
}
}
impl<'a> From<&WireExpr<'a>> for WireExpr<'a> {
#[inline]
fn from(key: &WireExpr<'a>) -> WireExpr<'a> {
key.clone()
}
}
impl<'a> From<&'a str> for WireExpr<'a> {
#[inline]
fn from(name: &'a str) -> WireExpr<'a> {
WireExpr {
scope: 0,
suffix: name.into(),
mapping: Mapping::Sender,
}
}
}
impl From<String> for WireExpr<'_> {
#[inline]
fn from(name: String) -> WireExpr<'static> {
WireExpr {
scope: 0,
suffix: name.into(),
mapping: Mapping::Sender,
}
}
}
impl<'a> From<&'a String> for WireExpr<'a> {
#[inline]
fn from(name: &'a String) -> WireExpr<'a> {
WireExpr {
scope: 0,
suffix: name.into(),
mapping: Mapping::Sender,
}
}
}
impl WireExpr<'_> {
#[cfg(feature = "test")]
#[doc(hidden)]
pub fn rand() -> Self {
use rand::{
distributions::{Alphanumeric, DistString},
Rng,
};
const MIN: usize = 2;
const MAX: usize = 64;
let mut rng = rand::thread_rng();
let scope: ExprId = rng.gen_range(0..20);
let suffix: String = if rng.gen_bool(0.5) {
let len = rng.gen_range(MIN..MAX);
Alphanumeric.sample_string(&mut rng, len)
} else {
String::new()
};
WireExpr {
scope,
suffix: suffix.into(),
mapping: Mapping::DEFAULT,
}
}
}