use serde::{Deserialize, Serialize};
pub const CHUNK_SIZE: usize = 4096;
pub const TOPIC_PREFIX: &str = "super_cereal";
pub const TYPE_NAME: &str = "SerialChunk";
pub const DEFAULT_HISTORY_DEPTH: i32 = 256;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SerialChunk {
pub seq: u64,
pub data: Vec<u8>,
}
impl SerialChunk {
pub fn new(seq: u64, data: Vec<u8>) -> Self {
Self { seq, data }
}
}
pub fn up_topic_name(channel: &str) -> String {
format!("{TOPIC_PREFIX}/{channel}/up")
}
pub fn down_topic_name(channel: &str) -> String {
format!("{TOPIC_PREFIX}/{channel}/down")
}
pub fn parse_channel_from_topic(topic_name: &str) -> Option<(String, String)> {
let rest = topic_name.strip_prefix(&format!("{TOPIC_PREFIX}/"))?;
let (channel, direction) = rest.rsplit_once('/')?;
if channel.is_empty() {
return None;
}
match direction {
"up" | "down" => Some((channel.to_string(), direction.to_string())),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_super_cereal_topics() {
assert_eq!(
parse_channel_from_topic("super_cereal/dev1/up"),
Some(("dev1".to_string(), "up".to_string()))
);
assert_eq!(
parse_channel_from_topic("super_cereal/my-channel/down"),
Some(("my-channel".to_string(), "down".to_string()))
);
assert!(parse_channel_from_topic("other/topic").is_none());
}
#[test]
fn topic_names_are_stable() {
assert_eq!(up_topic_name("dev1"), "super_cereal/dev1/up");
assert_eq!(down_topic_name("dev1"), "super_cereal/dev1/down");
}
}