use std::fmt::{self, Display};
use safelog::Redactable;
use tor_linkspec::OwnedChanTarget;
use crate::crypto::cell::HopNum;
#[derive(Debug, Clone)]
#[non_exhaustive]
pub(crate) enum HopDetail {
Relay(OwnedChanTarget),
#[cfg(feature = "hs-common")]
Virtual,
}
#[derive(Debug, Clone)]
pub struct PathEntry {
inner: HopDetail,
}
impl Display for PathEntry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.inner {
HopDetail::Relay(ct) => write!(f, "{}", ct),
#[cfg(feature = "hs-common")]
HopDetail::Virtual => write!(f, "<virtual hop>"),
}
}
}
impl Redactable for PathEntry {
fn display_redacted(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.inner {
HopDetail::Relay(ct) => Redactable::display_redacted(ct, f),
#[cfg(feature = "hs-common")]
HopDetail::Virtual => write!(f, "<virtual hop>"),
}
}
}
impl PathEntry {
pub fn as_chan_target(&self) -> Option<&(impl tor_linkspec::ChanTarget + use<>)> {
match &self.inner {
HopDetail::Relay(chan_target) => Some(chan_target),
#[cfg(feature = "hs-common")]
HopDetail::Virtual => None,
}
}
}
#[derive(Debug, Default, Clone)]
pub struct Path {
hops: Vec<PathEntry>,
}
impl Path {
pub fn n_hops(&self) -> usize {
self.hops.len()
}
pub fn hops(&self) -> &[PathEntry] {
&self.hops[..]
}
pub fn iter(&self) -> impl Iterator<Item = &PathEntry> + '_ {
self.hops.iter()
}
pub(crate) fn push_hop(&mut self, target: HopDetail) {
self.hops.push(PathEntry { inner: target });
}
pub(super) fn first_hop(&self) -> Option<HopDetail> {
self.hops.first().map(|ent| ent.inner.clone())
}
pub(crate) fn all_hops(&self) -> impl DoubleEndedIterator<Item = &HopDetail> + '_ {
self.hops.iter().map(|ent| &ent.inner)
}
pub(crate) fn last_hop_num(&self) -> Option<HopNum> {
let n = self.n_hops();
let idx: u8 = n.checked_sub(1)?.try_into().ok()?;
Some(idx.into())
}
}