use std::{borrow::Cow, fmt, str};
use heck::ToLowerCamelCase;
use serde::{Deserialize, Serialize};
use super::EmptyStreamName;
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Category<'a>(pub(crate) Cow<'a, str>);
impl<'a> Category<'a> {
pub const CATEGORY_TYPE_SEPARATOR: char = ':';
pub const COMPOUNT_TYPE_SEPARATOR: char = '+';
pub fn new(category: impl Into<Cow<'a, str>>) -> Result<Self, EmptyStreamName> {
let category = category.into();
Ok(Category(category))
}
pub fn from_parts(
entity_name: impl Into<String>,
types: &[&str],
) -> Result<Self, EmptyStreamName> {
let mut s = entity_name.into();
if s.is_empty() {
return Err(EmptyStreamName);
}
if !types.is_empty() {
s.push(Self::CATEGORY_TYPE_SEPARATOR);
for (i, ty) in types.into_iter().enumerate() {
if i > 0 {
s.push(Self::COMPOUNT_TYPE_SEPARATOR);
}
s.push_str(ty);
}
}
Ok(Category(Cow::Owned(s)))
}
pub fn into_static(self) -> Category<'static> {
Category(Cow::Owned(self.0.into_owned()))
}
pub fn normalize(category: &str) -> String {
category.to_lower_camel_case()
}
pub fn entity_name(&self) -> &str {
self.split_once(Self::CATEGORY_TYPE_SEPARATOR)
.map(|(name, _)| name)
.unwrap_or(&self.0)
}
}
impl_eq! { Category<'a>, &'b str }
impl_eq! { Category<'a>, String }
impl_as_ref_str! { Category, Category<'a>, Category<'static> }