pub mod keepalive;
pub mod nack;
pub mod retry;
use anyhow::Result;
use wacore_binary::{Node, NodeRef};
pub trait ProtocolNode: Sized {
fn tag(&self) -> &'static str;
fn into_node(self) -> Node;
fn try_from_node_ref(node: &NodeRef<'_>) -> Result<Self>;
fn try_from_node(node: &Node) -> Result<Self> {
Self::try_from_node_ref(&node.as_node_ref())
}
}
pub trait ParseStringEnum: Sized {
fn parse_from_str(s: &str) -> Result<Self>;
}
pub fn parse_string_enum<T: ParseStringEnum>(s: &str) -> Result<T> {
T::parse_from_str(s)
}
#[macro_export]
macro_rules! define_simple_node {
(
$(#[$meta:meta])*
$vis:vis struct $name:ident($tag:literal) {
$(
$(#[$field_meta:meta])*
#[attr($attr_name:literal)]
$field_vis:vis $field:ident : $field_type:ty $(= $default:expr)?
),* $(,)?
}
) => {
$(#[$meta])*
#[derive(Debug, Clone)]
$vis struct $name {
$(
$(#[$field_meta])*
$field_vis $field: $field_type,
)*
}
impl Default for $name {
fn default() -> Self {
Self {
$(
$field: $crate::define_simple_node!(@default $($default)?),
)*
}
}
}
impl $crate::protocol::ProtocolNode for $name {
fn tag(&self) -> &'static str {
$tag
}
fn into_node(self) -> wacore_binary::Node {
wacore_binary::builder::NodeBuilder::new($tag)
$(.attr($attr_name, self.$field.to_string()))*
.build()
}
fn try_from_node_ref(node: &wacore_binary::NodeRef<'_>) -> anyhow::Result<Self> {
if node.tag != $tag {
return Err(anyhow::anyhow!("expected <{}>, got <{}>", $tag, node.tag));
}
Ok(Self {
$(
$field: node.attrs().optional_string($attr_name)
.map(|s| s.to_string())
.unwrap_or_else(|| $crate::define_simple_node!(@default $($default)?)),
)*
})
}
}
};
(@default $default:expr) => { $default.to_string() };
(@default) => { String::new() };
}
#[macro_export]
macro_rules! define_empty_node {
(
$(#[$meta:meta])*
$vis:vis struct $name:ident($tag:literal)
) => {
$(#[$meta])*
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
$vis struct $name;
impl $crate::protocol::ProtocolNode for $name {
fn tag(&self) -> &'static str {
$tag
}
fn into_node(self) -> wacore_binary::Node {
wacore_binary::builder::NodeBuilder::new($tag).build()
}
fn try_from_node_ref(node: &wacore_binary::NodeRef<'_>) -> anyhow::Result<Self> {
if node.tag != $tag {
return Err(anyhow::anyhow!("expected <{}>, got <{}>", $tag, node.tag));
}
Ok(Self)
}
}
};
}
#[macro_export]
macro_rules! define_validated_string {
(
$(#[$meta:meta])*
$vis:vis struct $name:ident(max_len = $max_len:expr, name = $display_name:literal)
) => {
$(#[$meta])*
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
$vis struct $name(String);
impl $name {
pub fn new(value: impl Into<String>) -> anyhow::Result<Self> {
let s = value.into();
if s.chars().count() > $max_len {
return Err(anyhow::anyhow!(
"{} exceeds {} characters",
$display_name,
$max_len
));
}
Ok(Self(s))
}
pub fn new_unchecked(value: impl Into<String>) -> Self {
Self(value.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
pub fn into_string(self) -> String {
self.0
}
}
impl std::fmt::Display for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl AsRef<str> for $name {
fn as_ref(&self) -> &str {
&self.0
}
}
};
}