use core::fmt;
use bytes::Bytes;
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct StreamKey(Bytes);
impl StreamKey {
#[must_use]
pub fn from_bytes(bytes: impl Into<Bytes>) -> Self {
Self(bytes.into())
}
#[must_use]
pub fn from_slice(bytes: &[u8]) -> Self {
Self(Bytes::copy_from_slice(bytes))
}
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
#[must_use]
pub fn into_bytes(self) -> Bytes {
self.0
}
}
impl From<Bytes> for StreamKey {
fn from(bytes: Bytes) -> Self {
Self(bytes)
}
}
impl AsRef<[u8]> for StreamKey {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl fmt::Display for StreamKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Ok(s) = core::str::from_utf8(&self.0) {
return f.write_str(s);
}
f.write_str("0x")?;
for byte in &self.0 {
write!(f, "{byte:02x}")?;
}
Ok(())
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used, reason = "test code")]
mod tests {
use super::StreamKey;
use bytes::Bytes;
#[test]
fn round_trips_bytes_including_non_utf8() {
let raw = Bytes::from_static(&[0x00, 0xff, 0x42]);
let key = StreamKey::from_bytes(raw.clone());
assert_eq!(key.as_bytes(), &[0x00, 0xff, 0x42]);
assert_eq!(key.clone().into_bytes(), raw);
assert_eq!(StreamKey::from_slice(&[0x00, 0xff, 0x42]), key);
}
#[test]
fn display_is_the_string_for_utf8_ids() {
assert_eq!(
StreamKey::from_slice(b"account-123").to_string(),
"account-123"
);
assert_eq!(StreamKey::from_slice(b"").to_string(), "");
}
#[test]
fn display_is_hex_for_non_utf8_ids() {
assert_eq!(
StreamKey::from_slice(&[0x00, 0xff, 0x42]).to_string(),
"0x00ff42"
);
}
}