use std::{borrow::Cow, collections::HashMap};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SegmentKind {
Static,
Group,
Param,
CatchAll,
}
#[doc(hidden)]
#[derive(Debug, Clone)]
pub struct Segment {
module_path: &'static str,
kind: Option<SegmentKind>,
rename: Option<Cow<'static, str>>,
}
impl Segment {
#[must_use]
pub const fn new(
module_path: &'static str,
kind: Option<SegmentKind>,
rename: Option<Cow<'static, str>>,
) -> Self {
Self {
module_path,
kind,
rename,
}
}
#[must_use]
pub fn module_path(&self) -> &'static str {
self.module_path
}
#[must_use]
pub fn kind(&self) -> Option<&SegmentKind> {
self.kind.as_ref()
}
#[must_use]
pub fn rename(&self) -> Option<&str> {
self.rename.as_deref()
}
}
#[cfg(feature = "discover")]
inventory::collect!(Segment);
#[doc(hidden)]
#[derive(Debug, Default, Clone)]
pub(crate) struct Segments {
segments: HashMap<&'static str, Segment>,
}
impl Segments {
pub fn new() -> Self {
Segments::default()
}
#[track_caller]
pub fn register(&mut self, path: &'static str, segment: Segment) {
if let Some(existing) = self.segments.insert(path, segment) {
panic!(
"duplicate segment specifier in `{}`",
existing.module_path()
)
}
}
pub fn get(&self, path: &str) -> Option<&Segment> {
self.segments.get(path)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn test_segment() -> Segment {
Segment::new("my_crate::test", Some(SegmentKind::Static), None)
}
#[test]
fn register_and_get() {
let mut segments = Segments::new();
segments.register("foo", test_segment());
let seg = segments.get("foo").unwrap();
assert_eq!(seg.module_path(), "my_crate::test");
assert_eq!(seg.kind(), Some(&SegmentKind::Static));
assert_eq!(seg.rename(), None);
}
#[test]
fn get_missing_returns_none() {
let segments = Segments::new();
assert!(segments.get("nope").is_none());
}
#[test]
#[should_panic(expected = "duplicate segment specifier")]
fn register_duplicate_panics() {
let mut segments = Segments::new();
segments.register("foo", test_segment());
segments.register("foo", test_segment());
}
}