use std::collections::HashMap;
use std::fmt;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ControlSessionId(pub String);
impl ControlSessionId {
pub fn new(project_id: &str, n: u64) -> Self {
Self(format!("{project_id}-{n}"))
}
pub fn as_str(&self) -> &str {
&self.0
}
pub fn parse_parts(&self) -> Option<(&str, u64)> {
let s = self.0.as_str();
let dash = s.rfind('-')?;
let suffix = &s[dash + 1..];
let n: u64 = suffix.parse().ok()?;
Some((&s[..dash], n))
}
}
impl fmt::Display for ControlSessionId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
#[derive(Debug, Default)]
pub struct SessionCounter {
counters: HashMap<String, u64>,
}
impl SessionCounter {
pub fn next(&mut self, project_id: &str) -> ControlSessionId {
let n = self.counters.entry(project_id.to_owned()).or_insert(0);
let id = ControlSessionId::new(project_id, *n);
*n += 1;
id
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn control_session_id_display() {
let id = ControlSessionId::new("trusty-tools", 3);
assert_eq!(id.to_string(), "trusty-tools-3");
assert_eq!(id.as_str(), "trusty-tools-3");
}
#[test]
fn control_session_id_parse() {
let id = ControlSessionId::new("my-proj", 0);
let (proj, n) = id.parse_parts().expect("should parse");
assert_eq!(proj, "my-proj");
assert_eq!(n, 0);
}
#[test]
fn control_session_id_parse_project_with_dashes() {
let id = ControlSessionId("trusty-tools-2".to_owned());
let (proj, n) = id.parse_parts().expect("should parse");
assert_eq!(proj, "trusty-tools");
assert_eq!(n, 2);
}
#[test]
fn control_session_id_parse_invalid() {
let id = ControlSessionId("no-number".to_owned());
assert!(id.parse_parts().is_none());
}
#[test]
fn session_counter_monotonic() {
let mut counter = SessionCounter::default();
let a = counter.next("proj");
let b = counter.next("proj");
let c = counter.next("other");
assert_eq!(a.as_str(), "proj-0");
assert_eq!(b.as_str(), "proj-1");
assert_eq!(c.as_str(), "other-0");
let d = counter.next("proj");
assert_eq!(d.as_str(), "proj-2");
}
}