use std::fmt;
use std::sync::Arc;
macro_rules! arc_str_newtype {
($(#[$meta:meta])* $Name:ident) => {
$(#[$meta])*
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct $Name(Arc<str>);
impl serde::Serialize for $Name {
fn serialize<S: serde::Serializer>(&self, s: S) -> std::result::Result<S::Ok, S::Error> {
s.serialize_str(&self.0)
}
}
impl<'de> serde::Deserialize<'de> for $Name {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> std::result::Result<Self, D::Error> {
let s = String::deserialize(d)?;
Ok(Self(Arc::from(s.as_str())))
}
}
impl $Name {
pub fn new(s: impl Into<String>) -> Self {
Self(Arc::from(s.into().as_str()))
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for $Name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
impl From<&str> for $Name {
fn from(s: &str) -> Self { Self(Arc::from(s)) }
}
impl From<String> for $Name {
fn from(s: String) -> Self { Self(Arc::from(s.as_str())) }
}
};
}
arc_str_newtype!(
AppName
);
arc_str_newtype!(
StreamId
);
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct StreamKey {
pub app: AppName,
pub stream_id: StreamId,
}
impl StreamKey {
pub fn new(app: impl Into<AppName>, stream_id: impl Into<StreamId>) -> Self {
Self {
app: app.into(),
stream_id: stream_id.into(),
}
}
}
impl fmt::Display for StreamKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}/{}", self.app, self.stream_id)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn newtypes_are_cheap_clones_with_value_equality() {
let a = AppName::from("live");
let b = a.clone();
assert_eq!(a, b);
assert_eq!(a.as_str(), "live");
assert!(std::ptr::eq(a.as_str().as_ptr(), b.as_str().as_ptr()));
}
#[test]
fn stream_key_display_is_app_slash_stream() {
let key = StreamKey::new("live", "cam-1");
assert_eq!(key.to_string(), "live/cam-1");
}
#[test]
fn identifiers_roundtrip_through_serde() {
let key = StreamKey::new("vod", "movie");
let json = serde_json::to_string(&key).expect("serialize");
let back: StreamKey = serde_json::from_str(&json).expect("deserialize");
assert_eq!(key, back);
}
}