#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
serde(rename_all = "lowercase")
)]
#[non_exhaustive]
pub enum PipeStatus {
Idle,
Direct,
Relayed,
Closed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum CloseReason {
Shutdown,
ListenerFailed,
}
impl CloseReason {
pub const fn as_str(self) -> &'static str {
match self {
Self::Shutdown => "shutdown",
Self::ListenerFailed => "listener_failed",
}
}
}
impl PipeStatus {
pub const fn as_str(self) -> &'static str {
match self {
Self::Idle => "idle",
Self::Direct => "direct",
Self::Relayed => "relayed",
Self::Closed => "closed",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[non_exhaustive]
pub struct PeerView {
pub fingerprint: String,
pub path: PipeStatus,
pub rtt_ms: Option<u64>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_status_renders_a_distinct_stable_identifier() {
let all = [
PipeStatus::Idle,
PipeStatus::Direct,
PipeStatus::Relayed,
PipeStatus::Closed,
];
let rendered: Vec<&str> = all.iter().map(|s| s.as_str()).collect();
assert_eq!(rendered, ["idle", "direct", "relayed", "closed"]);
let mut deduped = rendered.clone();
deduped.sort_unstable();
deduped.dedup();
assert_eq!(
deduped.len(),
rendered.len(),
"identifiers must be distinct"
);
}
#[test]
fn every_close_reason_renders_a_distinct_stable_identifier() {
let all = [CloseReason::Shutdown, CloseReason::ListenerFailed];
let rendered: Vec<&str> = all.iter().map(|r| r.as_str()).collect();
assert_eq!(rendered, ["shutdown", "listener_failed"]);
let mut deduped = rendered.clone();
deduped.sort_unstable();
deduped.dedup();
assert_eq!(
deduped.len(),
rendered.len(),
"identifiers must be distinct"
);
}
#[test]
fn a_failure_is_not_equal_to_a_deliberate_close() {
assert_ne!(CloseReason::ListenerFailed, CloseReason::Shutdown);
}
}