use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Hash)]
#[serde(rename_all = "kebab-case")]
pub struct TopicPermission {
action: Action,
resource: Resource,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Copy, Hash)]
pub enum Action {
#[serde(alias = "publish")]
Publish,
#[serde(alias = "subscribe")]
Subscribe,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Hash)]
#[serde(rename_all = "kebab-case")]
struct Resource {
#[serde(rename = "type")]
resource_type: String,
stream: String,
prefix: String,
topic: String,
}
impl TopicPermission {
pub fn new(
action: Action,
stream: impl Into<String>,
prefix: impl Into<String>,
topic_pattern: impl Into<String>,
) -> Self {
let resource = Resource::new(stream, prefix, topic_pattern);
Self { resource, action }
}
pub fn full_qualified_topic_name(&self) -> String {
format!(
"{}/{}/{}",
self.resource.prefix, self.resource.stream, self.resource.topic
)
}
pub fn prefix(&self) -> &str {
&self.resource.prefix
}
pub fn stream(&self) -> &str {
&self.resource.stream
}
pub fn topic_pattern(&self) -> &str {
&self.resource.topic
}
pub fn action(&self) -> Action {
self.action
}
}
impl Resource {
pub fn new(
stream: impl Into<String>,
prefix: impl Into<String>,
topic_pattern: impl Into<String>,
) -> Self {
Self {
stream: stream.into(),
prefix: prefix.into(),
topic: topic_pattern.into(),
resource_type: "topic".to_string(), }
}
}
impl std::fmt::Display for Action {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::Publish => write!(f, "publish"),
Self::Subscribe => write!(f, "subscribe"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_topic_permission_new() {
let topic_permission = TopicPermission::new(Action::Publish, "stream", "prefix", "topic/#");
assert_eq!(topic_permission.action(), Action::Publish);
assert_eq!(topic_permission.stream(), "stream");
assert_eq!(topic_permission.prefix(), "prefix");
assert_eq!(topic_permission.topic_pattern(), "topic/#");
}
#[test]
fn test_resource_new() {
let resource = Resource::new("stream", "prefix", "topic/#");
assert_eq!(resource.stream, "stream");
assert_eq!(resource.prefix, "prefix");
assert_eq!(resource.topic, "topic/#");
}
#[test]
fn test_action_display() {
let action = Action::Publish;
assert_eq!(action.to_string(), "publish");
let action = Action::Subscribe;
assert_eq!(action.to_string(), "subscribe");
}
}