use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Route {
pub key: String,
pub session: Option<String>,
}
impl Route {
pub fn new(key: impl Into<String>, session: impl Into<String>) -> Self {
let session = session.into();
Route {
key: key.into(),
session: (!session.is_empty()).then_some(session),
}
}
pub fn bare(key: impl Into<String>) -> Self {
Route {
key: key.into(),
session: None,
}
}
pub fn parse(s: &str) -> Self {
match s.split_once('#') {
Some((key, session)) if !session.is_empty() => Route {
key: key.to_string(),
session: Some(session.to_string()),
},
_ => Route::bare(s),
}
}
pub fn session(&self) -> Option<&str> {
self.session.as_deref()
}
}
impl fmt::Display for Route {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.session {
Some(s) => write!(f, "{}#{}", self.key, s),
None => write!(f, "{}", self.key),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trips_session_scoped() {
let r = Route::new("KEY", "s12");
assert_eq!(r.to_string(), "KEY#s12");
assert_eq!(Route::parse("KEY#s12"), r);
assert_eq!(r.session(), Some("s12"));
}
#[test]
fn empty_session_is_bare() {
assert_eq!(Route::new("KEY", ""), Route::bare("KEY"));
assert_eq!(Route::new("KEY", "").to_string(), "KEY");
assert_eq!(Route::parse("KEY").session(), None);
assert_eq!(Route::parse("KEY#").session(), None, "trailing # is bare");
}
#[test]
fn parse_splits_on_the_separator() {
let r = Route::parse("KEY#abcd");
assert_eq!(r.key, "KEY");
assert_eq!(r.session(), Some("abcd"));
}
}